I'm trying to pass a variable to a child object of my parent object, but its returning undefined. (clearly I'm not sure how the scoping of a JS object works).
var parent = {
pid: '565',
child: {
cid: this.pid + '_child_789',
sayHello: function(){
alert('My id is ' + this.cid);
}
}
}
Calling parent.child.sayHello() logs the this.cid as undefined.
I'm (incorrectly) thinking that the child would inherit the pid property and could be referred to by this.pid, but it cannot.
Is there a way to do this without hardcoding the pid value?
I know I could do parent.child.cid = parent.pid + '_child_789' after creating the object but that is not scalable or practical for me.
You cannot access properties like that in your object literal. I would go into more detail, however, this question has already been answered several times. Please review the following questions:
JavaScript: Access own Object Property inside Array Literal
Can a JavaScript object property refer to another property of the same object?
Related
I have an example, after the line toy.type = 'break';I was expecting the next line would give me the value as "break" but instead gave "soft". Why isnt changing the parent property not reflecting when accessed using child object . Isnt the prototypal inheritance just a refernce to the base object?
const toy = {
init : function(type)
{
this.type = type
},
display : function()
{
console.log(this.type)
}
}
const softToy = Object.create(toy);
softToy.init('soft');
softToy.display();
toy.type = 'break';
softToy.display();
When you access an object, JavaScript searches up the prototype chain until it finds an object with that property.
Because softToy has its own type property, you get the value of that. If it didn't have its own type property then the prototype chain would be followed to the toy object and the type property from there would be accessed instead.
In other words, you get the closest version of the property not the most recently changed version.
I'm trying to get my head around prototype inheritance in Javascript. I think I got the basic concept, but when I was playing around with this I ran into the following which still has me puzzled.
There is a very similar question and answer here but it doesn't fully answer why this is happening, at least not for me.
I create a new object like this:
var User = {
username: "",
name: {
first: "",
last: ""
}
}
Next I create two "instances" of that object:
var user1 = Object.create(User);
var user2 = Object.create(User);
Now I set the name property like so:
user1.name = { first: "John", last: "Jackson"}
user2.name = { first: "James", last: "Jameson"}
Now I do
alert(user1.name.first) \\ -> John
alert(user2.name.first) \\ -> James
All as expected. So far so good.
However, if I set the name.first property like this:
user1.name.first = "John";
user2.name.first = "James";
and I get
alert(user1.name.first) \\ -> James
alert(user2.name.first) \\ -> James
Clearly now the property is being set on the prototype object User (or rather the contained name object) instead of overriding it in the current object user1. Why does that occur?
Further if I do
user1.name.middle = "Mortimer"
I can now do
alert(User.name.middle) // -> Mortimer
which is not what I would expect. Generally, whenever a property is set on a derived object, that object either already has that property as an ownProperty in which case the value is simply assigned, or the property is newly created as an ownProperty on the derived object, overriding the prototype property. Just like happens when I assign to user1.name.
So why does assigning to an object contained in the prototype object cause such (at least to me) unexpected and counter-intuitive behavior?
The way I understand it, when the assignment is made the first check is to see if user1 has an ownProperty called name, which it doesn't. If this were a read operation the prototype property would now be looked up and User checked to see if it has ownProperty name. But since this is a set operation why walk the prototype chain when usually a missing ownProperty is simply created?
But since this is a set operation why walk the prototype chain when usually a missing ownProperty is simply created?
When you say user1.name.first = "John", the user1.name part has to be resolved before the .first property can be retrieved or set. And in your example the user1.name part only exists on the prototype object, so it is that object whose .first property you are setting.
Similarly, when you say user1.name.middle = "Mortimer", again the user1.name part resolves to the nested object from the prototype, so then you create a .middle property on that object, which is why User.name.middle also returns "Mortimer".
If you said user1.name.first and user1.name could not be resolved (on the current object or in its prototype chain) then you'd have a TypeError: Cannot set property 'first' of undefined. (You can try that concept with your existing code by saying user1.address.street = "something" - you'd get the TypeError, because user1.address doesn't exist on user1 or its prototype chain.)
Since you've already read over similar questions and answers and still seem to be having trouble understanding the behavior, I'll try to make my explanation as clear as possible. Here is where I think you are going wrong (emphasis mine):
Generally, whenever a property is set on a derived object, that object either already has that property as an ownProperty in which case the value is simply assigned, or the property is newly created as an ownProperty on the derived object, overriding the prototype property. Just like happens when I assign to user1.name.
The problem here is that you assume that user.name.first counts as "a property . . . set on a derived object" (an instance of User). However, this is simply not the case. In JavaScript, inheritance of properties is only shallow (a single layer deep). user.name is just an object value shared by reference through the prototype, so modifications to it from one place are reflected everywhere.
Think of user1.name and user2.name like firstReference and secondReference in the following example snippet, and hopefully the behavior will seem a bit clearer to you.
var User = {
username: "",
name: {
first: "",
last: ""
}
}
var firstReference = User.name
var secondReference = User.name
firstReference.name.first = 'First!'
console.log(secondReference.name) //=> 'First!' (logical and expected result)
The Object.create method creates an object using the first parameter as a prototype, and the second, optional, parameter is an additional object of own properties.
I think the problem here is that name is, by definition, in the prototype, and so not an own property.
If you want separate properties, then you should use the second parameter. The prototype is where you store methods and shared properties.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
has more details.
The key is that you want both prototype and own properties.
So the problem, i have data that i call by using window.blah.blah and it will spit out info based on a user or an item in a database.
Now my problem is that i want to use the window.blah.blah with a dynamic appendage so like window.blah.blah.VARIABLE1
i have tried window.blah.blah.instances[variable] but i get a typeerror saying the value of variable is not defined (so if variable = test1 the error would be TypeError: Cannot read property 'test1' of undefined. variable is generated so it can be test1 test2 that correspond to stored objects.
if it helps i am using the call within a loop that is using it to get access a stored json obj with different object names.
also if I one of the objects is called test1 and i do window.blah.blah.test1 it accesses the object but window.blah.blah.instances[test1] gets the above error.
What am i doing wrong?
Perhaps the syntax you are looking for is window.blah.blah[VARIABLE1]
(assuming the blahs are objects.)
note that storing data on window is typically a bad idea, so for the following example, I'll move the top-level object from the global space (accessed through window) into a local variable:
var myObj = {
blah: {
blah: {}
}
};
var fooVar == 'foo';
function getMyDynamicVariable() {
return "foo"; //really this would by some dynamically generated string
}
//example usage:
myObj.blah.blah[getMyDynamicVariable()];
// OR
myObj.blah.blah[fooVar];
// would be the same as
myObj.blah.blah.foo //(in this exact example, where all functions and variables contain the string 'foo'.)
Let's say there is a simple object literal which name will never change:
var car = {
wheels : 4,
construct : function() {
var that = this;
setTimeout(function() {
console.log(that.wheels);
console.log(car.wheels);
}, 500);
}
};
My question is: Which way is better? Referencing by the object's name or creating a new variable (which may take some time and memory and probbaly must be done in multiple functions)?
Within the object, you should always refer to the object via this (or a copy of it, e.g. that, if required) to prevent the following breakage:
var car = ...
// do stuff
car = undefined; // or anything else, perhaps by a code hacker in the JS console
// class is now broken
You should treat the variable name that happens to have been given to your object on the outside as unknown to you, and subject to change.
Someone else might call it something else, there might be multiple names, the name might suddenly point at some other object altogether. Such variables are for the benefit of the "owners" of references to the object, and not for the object itself.
The context (this) is naturally the object that the property is being requested on, but there are no arguments passed to the getter function. I'd like to be able to get the name of the property being requested without using closures but it's looking like that's the only way to do it.
Object.defineProperty( someObj, "prop1", { get: genericGetter } );
Object.defineProperty( someObj, "prop2", { get: genericGetter } );
function genericGetter() {
// i want to figure out whether this is called on prop1 or prop2
}
Can I tell what property a generic getter/setter applies to in its
body?
That's not how getters work. A property of an object can either have a value or a get function. If the property has a value, then reading the property:
var x = obj.prop;
returns that value. However, if a property has a get function instead, then reading that property triggers that function. So, you use getters if the value of a certain property has to be computed dynamically, or if you want to perform certain operations whenever the property is read.
For instance, .innerHTML requires a getter, because its value is not stored statically, but computed on access:
var html = div.innerHTML;
Here, the browser has to serialize the DOM structure that is contained within the div element.
So, if you want a .get() function that retrieves various properties (Backbone.js has such a function), then you're not looking for getters.
The simplest implementation of what you want would be:
someObj.getProp = function ( name ) {
// perform required tasks
return this[ name ];
};