I like to think I understand JavaScript, but I found something unexpected today and I was hoping someone could explain to me why it happens.
Take this code
var animalData = {
cow:"cow",
sheep:"sheep",
getCow:function()
{
return this.cow;
},
animalList:[
{
animalId:this.cow,
label:"This is a cow"
},
{
animalId:this.sheep,
label:"This is a sheep"
}
]
};
console.log(animalData.getCow());
console.log(JSON.stringify(animalData.animalList,null," "))
The output is not what I was expecting. Calling animalData.getCow()
results in "cow"
just as you would expect. But it's what gets return by the second console.log
that confuses me.
[
{
"label": "This is a cow"
},
{
"label": "This is a sheep"
}
]
In other words, the object removes the animalId
property entirely from the objects defined. I was expecting this
[
{
"animalId":"cow",
"label": "This is a cow"
},
{
"animalId":"sheep",
"label": "This is a sheep"
}
]
And I could understand maybe this
[
{
"animalId":undefined,
"label": "This is a cow"
},
{
"animalId":undefined,
"label": "This is a sheep"
}
]
But why does the animalId
property get removed entirely?
Can anyone explain what's going on under the surface to cause this behaviour? I'm guessing that the this
keyword does not work because the properties are undefined when it is invoked, but why does it remove the property entirely?
NB: I'm not looking for a workaround, that's easy enough to do - just interested in why it happens.
JSFiddle here
“this” is not bound In JavaScript, keyword this behaves unlike most other programming languages. It can be used in any function, even if it's not a method of an object. The value of this is evaluated during the run-time, depending on the context.
JavaScript's this keyword is one of the hardest aspects of the language to grasp. But it is critically important for writing more advanced JavaScript code. In JavaScript, the this keyword allows us to: Reuse functions in different execution contexts.
$ is simply a valid JavaScript identifier. JavaScript allows upper and lower letters, numbers, and $ and _ . The $ was intended to be used for machine-generated variables (such as $0001 ). Prototype, jQuery, and most javascript libraries use the $ as the primary base object (or function).
The this keyword refers to the current object in a method or constructor. The most common use of the this keyword is to eliminate the confusion between class attributes and parameters with the same name (because a class attribute is shadowed by a method or constructor parameter).
At the point the object is initialised, this
refers to the outer context, which won't have cow
and sheep
properties. As you thought, that will result in the animalId
s being undefined
.
JSON.stringify
does certain things with undefined
properties, namely:
If
undefined
, a function, or a symbol is encountered during conversion it is either omitted (when it is found in an object) or censored tonull
(when it is found in an array).
Which is why you don't see them.
First of all, you are correct your last example, this is what you are trying to stringify:
[
{
"animalId":undefined,
"label": "This is a cow"
},
{
"animalId":undefined,
"label": "This is a sheep"
}
]
And, because those values are undefined JSON.stringify
simply omits them.
Why the values above are undefined is because the this
keyword in this.cow
refers to the current scope, which is actually the window
Object as it is not inside any other function.
Why it makes sense to omit keys with undefined
values? Because whether they exist or not, if you try to access object.key
you will get the correct value: undefined
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With