I am looking for a way to get the name of an object property like this:
let o = {
first: 1,
second: 2
};
function q(prop) {
// return name of prop
}
console.log(q(o.first));
// should return "first"
I am not even sure this is possible, but I am just asking.
The main use case for this is given by dynamic specification of requested attributes while keeping the advantages of using intellisense which can be quite significant for large projects and refactoring purpose.
I am not even sure this is possible...
Good instinct! It isn't. When you do:
q(o.first);
the value of the o.first property (1) is passed into q. Nothing about the object or its property is passed to q, just the value 1.
If you know what object the value came from, and if that object had only one property with a matching value, you could figure it out. But of course, one or both of those won't be true the vast majority of the time. In the general case, no, there's nothing to tell you that it came from o.first.
You try this with slight modification of your code
function q(obj,prop) {
if(obj.hasOwnProperty(prop))
return prop;
else
return null;
}
console.log(q(o,o.first));
Hope this help.
Related
Without explaining the details of the project I'm working on in too much detail, I am trying to determine a way in which I can either implement an event listener for when document.getElementById().value is accessed, or override it in a similar way to an object, and define custom behaviour for the getting and setting of this value. Is this possible?
I've tried the following, to no avail:
Object.defineProperty(document.getElementById, 'nodeValue', {
get: function () {
console.log('document.getElementById value accessed');
return this.nodeValue;
},
set: function (value) {
console.log('document.getElementById value set');
this.nodeValue = value;
}
});
and the same as above but with value instead of nodeValue:
Object.defineProperty(document.getElementById, 'value', {
get: function () {
console.log('document.getElementById value accessed');
return this.value;
},
set: function (value) {
console.log('document.getElementById value set');
this.value = value;
}
});
Apologies if this seems a somewhat farfetched approach, the intricacies of JavaScript behind-the-scenes isn't something I am too familiar with. The above code does show what I am trying to achieve, however. I just don't know how!
I've spent some time on MDN trying to understand just how this works and from what I can gather, getElementById() returns an Element which inherits from the Node interface which contains a nodeValue, and I this that this nodeValue is what I am interested in, but I cannot be certain.
Edit: I'm looking for this behaviour to be generic, I have more than one (but an unknown number of) elements, so I'm not trying to apply this to a specific element.
First, modifying Element object is a bad idea. Extending it, is bad, but not as bad as modifying it. This is because, JavaScript implementation on web browser does not put details on how the underlying API works. For example,
1. Modify Element Object
We have a document as follows:
<div>
<h1 id="elem-id">Header Content</h1>
</div>
we could get its id by calling these instructions
let elem = document.getElementById('elem-id');
elem.getAttribute('id'); // 'elem-id';
We can modify getAttribute() by using:
Element.prototype.getAttribute = function (attributeKey) {
// Implement your own function here
return 'ok';
}
Next, when you call elem.getAttribute('id') it should return ok.
This is bad because there is no way to revert back to default implementation.
2. Extending Element Object
Next less bad stuff is, extending Object. We could simply do:
Element.prototype.getAttributeAndFireEvent = function (attributeKey) {
console.log(`getting attribute for ${attributeKey}`); // Could be an eventEmitter
return this.getAttribute(attributeKey);
}
then, we could use these methods by calling it like:
elem.getAttributeAndFireEvent('elem-id');
This will work but please be careful in modifying global object, it may cause unintended effect.
References:
In Javascript, can you extend the DOM?
Suppose I've a Set as a lookup table.
const myset = new Set(["key1", "key2", "key3", "keepMe"]);
I wanted to filter another array of some other keys (say mykeys) which are in myset.
const mykeys = ["ignoreMe", "keepMe", "ignoreMeToo", "key2"];
Question:
Why do I have to use
const filtered = mykeys.filter(k => myset.has(k))
instead of
const filtered = mykeys.filter(myset.has)
// TypeError: Method Set.prototype.has called on incompatible receiver undefined
i.e., why do I've to create an anonymous lambda function in filter? keys.has has same signature (argument - element, return boolean). A friend told me it's related to this.
Whereas mykeys.map(console.log) works without error (although not being of much use).
I came across this article at MDN and I still don't get why "'myset' is not captured as this". I understand the workaround but not the "why". Can anyone explain it with some details and references in a human friendly way?
Update: Thank you all for the responses. Maybe I wasn't clear about what I'm asking. I do understand the workarounds.
#charlietfl understood. Here's his comment, the thing I was looking for:
Because filter() has no implicit this where as set.has needs to have proper this context. Calling it inside anonymous function and manually adding argument makes the call self contained.
You could use thisArg of Array#filter with the set and the prototype of has as callback.
This pattern does not require a binding of an instance of Set to the prototype, because
If a thisArg parameter is provided to filter, it will be used as the callback's this value. Otherwise, the value undefined will be used as its this value. The this value ultimately observable by callback is determined according to the usual rules for determining the this seen by a function.
const
myset = new Set(["key1", "key2", "key3", "keepMe"]),
mykeys = ["ignoreMe", "keepMe", "ignoreMeToo", "key2"],
filtered = mykeys.filter(Set.prototype.has, myset);
console.log(filtered);
This is a fundamental design decision dating back to the first definition of the JavaScript language.
Consider an object
var myObjet = {
someValue: 0,
someFunction: function() {
return this.someValue;
}
};
Now, when you write
var myValue = myObject.someValue;
You get exactly what you have put in it, as if you had written
var myValue = 0;
Similarly, when you write
var myFunction = myObject.someValue;
You get exactly what you have put in it, as if you had written
var myFunction = (function() {
return this.someValue;
});
...except now, you are not in an object anymore. So this doesn't mean anything. Indeed, if you try
console.log(myFunction());
you will see
undefined
exactly as if you had written
console.log(this.someValue);
outside of any object.
So, what is this? Well, JavaScript decides it as follows:
If you write myObject.myFunction(), then when executing the myFunction() part, this is myObject.
If you just write myFunction(), then this is the current global object, which is generally window (not always, there are many special cases).
A number of functions can inject a this in another function (e.g. call, apply, map, ...)
Now, why does it do this? The answer is that this is necessary for prototypes. Indeed, if you now define
var myDerivedObject = Object.create(myObject);
myDerivedObjet.someValue = 42;
you now have an object based on myObject, but with a different property
someValue
console.log(myObject.someFunction()); // Shows 0
console.log(myDerivedObject.someFunction()); // Shows 42
That's because myObject.someFunction() uses myObject for this, while myDerivedObject.someFunction() uses myDerivedObject for this.
If this had been captured during the definition of someFunction, we would have obtained 0 in both lines, but this would also have made prototypes much less useful.
I've seen before that undefined semantically should only be used for variables that have been declared but not defined, and if a variable should at any point be set or unset, I should initially set it to null and check the variable against null rather than setting it back to undefined.
I'm wondering about the case where I am checking something that should be undefined, as in the case I am checking what an unset key in an object points to
i.e.
var eva = {'asuka': 2, 'rei': 0};
if I were to check eva['shinji'], I would have to check for undefined, because there are cases where I would not know all the possible keys that would be checked against.
I guess in this case, eva['shinji'] being undefined would be correct, though in the specific case of keys in objects, using ('shinji' in eva) would be best?
However, I have a feeling there may be other cases where objects that were unknown were checked against, that I could not use a 'in' for instead, but the case of object keys was most apparent to me.
In those cases, would it be best to check for undefined?
First of all, your statement is incorrect, should be:
var eva = {'asuka': 2, 'rei': ''};
Then you can find eva['asuka'] or eva.asuka will give 2.
If you want to check if a property inside an object.
There are multiple ways to do that.
You can simple check eva && eva.hasOwnProperty('asuka')
eva && typeof(eva.asuka) !== 'undefined'
3.
var found = false;
for (i in eva){
if (i == 'asuka') {
found = true;
break;
}
}
As mattclemens commented, if you do not understand the differences and best practices surrounding undefined vs null please check out the link he posted, or one of the other multitudes of blog/forum posts, books, or videos regarding this subject (i.e. duckduck something like "js best practices undefined null").
Based on the first paragraph of your question it seems you have a grasp on what they mean, and this question comes down to context...
I'm wondering about the case where I am checking something that should be undefined...
This seems like a loaded question to me. What does "should be undefined" mean? This tells me that your code never sets that property that "should be undefined" and you are assuming nothing else is setting it. But really, "should be undefined" doesn't make sense to me. You either know it's not because it's never been outside the current scope and you haven't defined it yourself, or you don't know and it's best practice to check whether it's defined before checking if it's null.
So I see this as 2 basic scenarios:
Internally/Privately created and used exclusively internal to code you control
Externally/Publicly created or crossing the public/private line
1. Internal/Private use only
In the first scenario the answer is simple: initialize the object with default values (falling back to null) for all properties that will ever exist on the object...
var eva = {'asuka': 2, 'rei': null};
...or since you have direct control over the object throughout its lifecycle, add properties explicitly as needed using the default operator...
eva.shinji = eva.shinji || null;
Then whenever you need to check the value of a specific property, your only concern is whether it is null. You will notice this strategy being employed in some of the most widely used js libraries, such as jQuery, where internal variables are only ever checked against null, or even assumed to exist within some contexts.
2. External/Public use at any point in the object's lifecycle
For objects you can't trust there are two approaches I would suggest, and which one is choosen depends, again, on the details of the context. If you are receiving some object, and will be using that object repeatedly or modifying the data you receive from it for internal use only, or if it is unsafe to change the value of the original object in any way, you may want to make your own copy of the object and then deal with that copy exclusively. Again, this is illustrated in libraries/frameworks, such as jQuery and AngularJS, where things like window and the undefined value itself, are passed in to the IIFE, and an internal copy is created/extended for internal use throughout the lifetime of the consumer.
However, this may be unnecessary overhead for your situation. Instead you could just verify the contents of eva when it crosses that external/internal boundary. The following example does so with the default operator.
function yourFunction(eva) {
eva = eva || {};
eva.asuka = eva.asuka || 2;
eva.rei = eva.rei || null;
}
Alternatively, you may have a string value or array of string values that are keys you wish to verify exist on the object. In that case please consider the following example using Object.keys(). This example also allows for the array of names of keys to be undefined.
function foo(eva, keysToFind) {
eva = eva || {};
keysToFind = keysToFind || ['asuka', 'shinji'];
var keysToCheck = Object.keys(eva);
for(var k in keysToFind) {
var keyName = keysToFind[k];
var keyIdx = keysToCheck.indexOf(keyName);
if(keyIdx == -1) {
eva[keyName] = null;
}
}
}
Finally, as RaymondM points out, you can take this a step further if you need to determine whether a property was added to the object literal, it's prototype, or inherited from a super/base class...
You can simple check eva && eva.hasOwnProperty('asuka')
Again, taking context in to consideration, if you have already identified the context as scenario 1 or 2 from above, and are checking any more than a single property's existence, then it will likely be more efficient to check for === null or typeof eva.asuka === 'undefined', respectively. Or even check if(eva && eva.asuka) { ... }, if you're certain asuka has been defined.
I'm working on some existing code that looks something like this:
return this.getMyObject() && this.getMyObject().myArray[0];
As far as I can tell it is checking that the object returned by getMyObject() exists before returning the first item in it's myArray property. How does this work and is it good form?
Update: The reason for my question came from the confusion over how the && operator can be used to return a property value and not a boolean result. After further thought, to make it more readable I refactored the line to:
return this.getMyObject() ? this.getMyObject().myArray[0] : undefined;
Obviously I am assuming here that the myArray property will exist.
That code works because of type coercion. Some people will tell you its good and some people will say always truly check something using typeof
if (typeof someVariable === 'undefined')
Even in examples below the above check isn't enough. I don't know what is better but that code as far as I am concerned isn't how I write it myself but it is accepted with a lot of javascript developers. There are times that code in the correct conditions can still pass the first check and yet throw an error accessing the property. Depends how controlled your situation is that determines, to me, if you should or shouldn't allow it.
Example of passing first check and failing:
var myObject = 1;
var test = myObject && myObject.myArray[0];
Or as #JamesThorpe pointed out in comment above:
var myObject = {};
var test = myObject && myObject.myArray[0];
Also people familiar with some coding languages but not JS might look at that code and not understand what it means where checking with an if and then returning the value might be a bit more readable to others, which is also a plus I think.
It's correct form. If there is no object returned by this.getMyObject() then function will return false in another case second part of condition will be executed and returned as a result of function. It's good practice to check if object exists before calling any method on it, because an error could occur if not to do so.
But you should check an existence of an object only if you are not sure whether it exists.
How to find the text description of what 'this' currently points to in javascript.
i have tried this.name but just get undefined.
this.toString() - I think that's the best you can get
EDIT: You can also try looping through the object's properties to see what it contains:
for (property in this) {
console.log(property);
}
If you're using Firebug you can use console.log(this). The console should then provide a clickable representation of whatever you've just logged, and clicking on it should take you to a more detailed explanation.
Well there's always typeof:
var type = typeof obj;
But, this is not foolproof as you will just get 'object' for objects...
Well, I'm still not entirely sure what you're wanting, but I've put this demo together, at JS Fiddle to give you an idea of a couple of the options available.
It rests on using:
$('#result').text(this.tagName.toLowerCase());
or
$('#result').text(typeof this);
Objects don't have names in JavaScript, it's as simple as that. A variable with a particular name could have an object as it's value, but that's as far as the relationship goes, the object retains no reference to the variable name that points to it. In fact, more than one variable may point to it. If a reference to an object is stored as a property on another object, you could iterate over that object's properties checking to see if the current property's value is the same object in the this value. For instance:
for (var k in someObj) {
if (this == someObj[k])
console.log(k + " points to this.");
}
I don't think there's a reason you'd ever need to do this, however.
No Firebug required (demo at http://jsfiddle.net/Y57ed/2/):
function usefulTypeof(obj) {
return obj === null ? "null" :
obj.constructor.toString().replace(/[^\w$\s]+/g, "").split(/\s+/)[1];
}