I don't understand why the following is happening:
function Class() {}
Class.prototype.foo = {a: 1};
Class.prototype.bar = 1;
x = new Class();
y = new Class();
y.foo.a = 2;
y.bar = 2;
x.foo.a; //2
x.bar; //1
When I set y.foo.a to 2, it seems to be performing the same operation as y.constructor.prototype.foo.a = 2. Why would this be, given that y.bar = 2 doesn't affect y.constructor.prototype.bar?
You are mixing prototype properties with properties that are local to the object instance. Using y.bar = 2, you are assigning an instance property (bar) to the instance y. In interpreting a property (bar) is first looked up within the instance itself. If it isn't found there, the lookup continues in the instances prototype. Now you assigned bar to y, so y.bar = 2, but instance x has no knowledge of it, so for x the lookup continues using its prototype (that's prototype.bar, still with value 1).
For y.foo.a, there is no instance property foo in y, so it's looked up in its prototype. There it's found, and the property a is assigned the new value. Because you are thereby changing a value of the Class.prototype property foo, it's also represented in x.
If you want to change bar in its prototype (so originating from instance y), you'll have to use the prototype of y's constructor (which is Class):
y.constructor.prototype.bar = 2;
May mr Douglas Crockford can clarify things for you (jump to around minute 23 in the video for prototypal inheritance)?
You are reading y.foo but assigning to y.bar. These are different operations with different semantics. Setting y.foo.bar must first read y.foo: it looks for the value of foo in y, fails to find it, then looks in y's prototype, discovers an object, and only then modifies that object. assigning y.bar simply looks up y and then modifies it. x.bar and y.bar then denote different objects, while x.foo and and y.foo denote the same object.
Reading an attribute does search in the prototype object, if it is not defined in the main object.
Setting an attribute does ever set it to the main object and NEVER to the prototype object.
Because of this, it is ever a bad idea to define something other than functions, or values that will never change in prototype objects.
To really understand what happens, I recommend you to experiment with the
__proto__
attribute. I know, not all browsers do support it, but it really helps you understand how prototyping in JavaScript works.
Related
So I was playing around the other day just to see exactly how mass assignment works in JavaScript.
First I tried this example in the console:
a = b = {};
a.foo = 'bar';
console.log(b.foo);
The result was "bar" being displayed in an alert. That is fair enough, a and b are really just aliases to the same object. Then I thought, how could I make this example simpler.
a = b = 'foo';
a = 'bar';
console.log(b);
That is pretty much the same thing, isn't it? Well this time, it returns foo not bar as I would expect from the behaviour of the first example.
Why does this happen?
N.B. This example could be simplified even more with the following code:
a = {};
b = a;
a.foo = 'bar';
console.log(b.foo);
a = 'foo';
b = a;
a = 'bar';
console.log(b);
(I suspect that JavaScript treats primitives such as strings and integers differently to hashes. Hashes return a pointer while "core" primitives return a copy of themselves)
In the first example, you are setting a property of an existing object. In the second example, you are assigning a brand new object.
a = b = {};
a and b are now pointers to the same object. So when you do:
a.foo = 'bar';
It sets b.foo as well since a and b point to the same object.
However!
If you do this instead:
a = 'bar';
you are saying that a points to a different object now. This has no effect on what a pointed to before.
In JavaScript, assigning a variable and assigning a property are 2 different operations. It's best to think of variables as pointers to objects, and when you assign directly to a variable, you are not modifying any objects, merely repointing your variable to a different object.
But assigning a property, like a.foo, will modify the object that a points to. This, of course, also modifies all other references that point to this object simply because they all point to the same object.
Your question has already been satisfyingly answered by Squeegy - it has nothing to do with objects vs. primitives, but with reassignment of variables vs. setting properties in the same referenced object.
There seems to be a lot of confusion about JavaScript types in the answers and comments, so here's a small introduction to JavaScript's type system:
In JavaScript, there are two fundamentally different kinds of values: primitives and objects (and there is no thing like a 'hash').
Strings, numbers and booleans as well as null and undefined are primitives, objects are everything which can have properties. Even arrays and functions are regular objects and therefore can hold arbitrary properties. They just differ in the internal [[Class]] property (functions additionally have a property called [[Call]] and [[Construct]], but hey, that's details).
The reason that primitive values may behave like objects is because of autoboxing, but the primitives themselves can't hold any properties.
Here is an example:
var a = 'quux';
a.foo = 'bar';
document.writeln(a.foo);
This will output undefined: a holds a primitive value, which gets promoted to an object when assigning the property foo. But this new object is immediately discarded, so the value of foo is lost.
Think of it like this:
var a = 'quux';
new String(a).foo = 'bar'; // we never save this new object anywhere!
document.writeln(new String(a).foo); // a completly new object gets created
You're more or less correct except that what you're referring to as a "hash" is actually just shorthand syntax for an Object.
In the first example, a and b both refer to the same object. In the second example, you change a to refer to something else.
here is my version of the answer:
obj = {a:"hello",b:"goodbye"}
x = obj
x.a = "bonjour"
// now obj.a is equal to "bonjour"
// because x has the same reference in memory as obj
// but if I write:
x = {}
x.a = obj.a
x.b = obj.b
x.a = "bonjour"
// now x = {a:"bonjour", b:"goodbye"} and obj = {a:"hello", b:"goodbye"}
// because x points to another place in the memory
You are setting a to point to a new string object, while b keeps pointing to the old string object.
In the first case you change some property of the object contained in the variable, in the second case you assign a new value to the variable. That are fundamentally different things. The variables a and b are not somehow magically linked by the first assignment, they just contain the same object. That's also the case in the second example, until you assign a new value to the b variable.
The difference is between simple types and objects.
Anything that's an object (like an array or a function) is passed by reference.
Anything that's a simple type (like a string or a number) is copied.
I always have a copyArray function handy so I can be sure I'm not creating a bunch of aliases to the same array.
ECMAScript 5
has defined a very common factory pattern for construction and inheritance, called Object.create(). I am simply passing in the object to
inherit from, and getting back a new object all properly wired up.
Consider the snippet:
var a = {
phrase: "Hello",
say: function(){ alert(this.phrase); }
};
var b = Object.create(a);
Is my understanding correct as reflected below?
When b is first created, it has a prototype-inherited property called
phrase, meaning that the property is not on the instance (b.phrase),
but actually on the prototype (b.prototype.phrase). If I were to
read the value of b.phrase at that point, JavaScript would implicitly
look it up, find it on the prototype, and return it to me.
b.say(); // alerts Hello
However, when I make the assignment of a new value to b.phrase, I see it doesn’t affects the inherited
b.prototype.phrase but have instead set (overridden) an instance property b.phrase that takes precedence over the inherited
b.prototype.phrase on future property accesses. Why?
b.phrase = "World";
a.say(); // alerts Hello >> This hasn't changed. Why?
b.say(); // alerts World
This happens because of the prototype chain. JavaScript runtime looks for own object's properties first, and if nothing is found, it looks for the property on its prototype, and so on.
In the other hand, you're not overriding a property, but you are just adding one to the whole object and it hides the prototype's one, and again, this happens because of how prototype chain works.
This is the way javascript property lookup/assignment work. If you want to update prototype property, you can create object inside prototype object.
var proto = {
fields: {
phrase: 'Hello'
},
say: function () { console.log(this.fields.phrase) }
};
var a = Object.create(proto);
a.fields.phrase = 'World';
proto.say();
a.say();
So, what is going on here?
a.fields.phrase = 'World' is equal to
var tmp = a.fields;
tmp.phrase = 'World';
a.fields === a.__proto__.fields // true
That is why property was updated in prototype.
In your example you just assign value to object and js engine does what you want – assigns value "World" with key "phrase" to object a, nothing weird
More info about how objects work in js
First take this statement
var b = Object.create(a);
This statement creates a new object, newObj(for instance). Now following things happen:
b points to newObj.
newObj is linked to a's object via [[prototype]] reference.
Till now newObj does not have any methods or properties.
Take b.Say() -- b will point to newObj,so first it tries to check whether newObj has Say() method, it doesn't have so it tries to delegate via [[prototype]] chain. As newObj's [[prototype]] link points to a's object. It tries to check whether Say() is present in a's object.So it finds the method there & execute it with the context of newObj. It prints 'Hello'
Take b.Phrase='world'
Here you are assigning phrase property to newObj object (pointed by 'b'). So from next time if you are trying to do b.Phrase it will not traverse up the [[Prototype]] chain (i.e to a's object), instead it will find the value in newObj itself.
Final b.Say()
As newObj does not have Say() method, it will traverse up the [[prototype]] chain, finds the method, & executes it in the context of newObj. And as newObj has phrase property so this.phrase returns 'world'
I wanted to try manually walking the prototype chain of a few objects just to see what I find along the way. However, I got stuck on the first one that I tried. Here's the code:
function MyObject() { }
var x = new MyObject();
console.log('--------------------------------------------');
console.log('x.constructor.name: ' + x.constructor.name);
console.log('x.constructor.prototype.constructor.name: ' + x.constructor.prototype.constructor.name);
console.log(x.constructor.prototype === Function.prototype ? 'Good guess.' : 'No, you are wrong.');
console.log(x.constructor === MyObject ? 'Good guess.' : 'No, you are wrong.');
console.log('--------------------------------------------');
The above code results in the following output in the Developer Tools Console of Google Chrome:
--------------------------------------------
x.constructor.name: MyObject
x.constructor.prototype.constructor.name: MyObject
No, you are wrong.
Good guess.
--------------------------------------------
It makes sense that x's constructor is the MyObject function, since x was instantiated using the new keyword on MyObject (this follows from the definition of a constructor). Because of this, I understand the first line of output (note: I started counting lines of output from zero on up). The second line, however, confuses me. I would like to know what MyObject's prototype is. Apparently, it isn't an object of type Function, as indicated by the 3rd line of output, which tells me that I'm wrong. The fourth line of output just reinforces the output from the first line.
On a more general note, I assumed that the correct way to walk the prototype chain of an object would be to go from the object in question to its constructor, and then from the constructor to the constructor's prototype, assuming that this last reference is not null. I assumed that this two-step process (consisting of going to the constructor, and then to the constructor's prototype) should be repeated until a null reference from a constructor to a prototype is reached, thus signifying the end of the prototype chain. This doesn't seem to be working, though, since application of this algorithm to the above scenario just leads to circular references.
In summary, I have two questions:
Why is x.constructor === x.constructor.prototype.constructor (or, in other words, why the circular references), and what kind of an object is x.constructor.prototype, anyway (or, in other words, how did it get instantiated / where did it come from)?
How can the above algorithm be corrected in order to correctly walk the prototype chain for object x?
Edit
I came across a similar question on StackOverflow here, but it doesn't explicity ask the correct way to walk the prototype chain. It does point out the circular references, though...
In Javascript terminology, an object a's "prototype" refers to the object from which a inherits properties. The standards-based way to access this is with Object.getPrototypeOf:
var protoOfA = Object.getPrototypeOf(a);
There's also the old way, non-standard but supported by some browsers:
var protoOfA = a.__proto__;
But if you have a function F, F.prototype does NOT refer the object from which F inherits anything. Rather, it refers to the object from which instances created by F inherit:
function F() {};
a = new F();
console.log(Object.getPrototypeOf(a) === F.prototype); // true
When you define a function, an object is created to serve as the prototype of instances created by that function, and this new object is stored in the function's prototype property.
--
Functions behave like objects in many ways (e.g., they can have properties) but they aren't exactly like other objects:
console.log(typeof a); // "object"
console.log(typeof F); // "function"
Their "prototypes" are ill-defined (example run in Chrome) (this is apparently a Chrome-specific behavior)
console.log(Object.getPrototypeOf(F)); // "function Empty() {}"
console.log(Empty); // ReferenceError: Empty is not defined
--
The constructor property is strange. The interpreter doesn't care about it. MDN says, confusingly:
Returns a reference to the Object function that created the instance's prototype.
Further, you can change the value of constructor on an object, but this has no effect on what the object is or how it behaves - it's merely descriptive.
--
So, to answer your questions:
Why is x.constructor === x.constructor.prototype.constructor
No good reason. This is arbitrary behavior browsers have converged on.
what kind of an object is x.constructor.prototype, anyway
In this example, t's x's prototype, the same as Object.getPrototypeOf(x). But in general you can't rely on x.constructor or anything derived from it, because it's arbitrary.
How can the above algorithm be corrected in order to correctly walk the prototype chain for object x?
for (var p = x ; p != null ; p = Object.getPrototypeOf(p)) {
// do something with p
}
Yeah, this can be a bit difficult to grasp at first. I cannot do better than provide you some links. These always help me out when I am in trouble.
http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
http://mckoss.com/jscript/object.htm
http://zeekat.nl/articles/constructors-considered-mildly-confusing.html
Q1: For the "why" see the references above. x.constructor.prototype is x.__proto__ that is the internal "real" prototype of x, at least in your case when no prototype and constructor properties were overwritten. It is created the moment you define the function MyObject.
Q2: Unfortunately you cannot do it this way. You can use the __proto__ property where it is supported, but see
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
All the resources I have found, it says that if we use Javascript prototype pattern, that functions' prototype is shared between all the objects for that particular type.
that means the following;
function TestObj(){
}
TestObj.prototype = {
cVar: 15,
increase: function(){
this.cVar++;
}
};
var a = new TestObj();
var b = new TestObj();
a.increase();
console.log(a.cVar); // 16
console.log(b.cVar); // 15 ??
Now my question is, shouldn't the b.cVar be 16? why is it 15 then? And if it is 15 that means the TestObj with protype is not shared between objects.
Do you know??
Yes, an object's prototype is shared between instances of the object, but the this.cVar++ looks a little bit misleading.
I think its easier to explain if you rewrite
this.cVar++;
as
this.cVar = this.cVar + 1;
The important thing is that this refers to the object instance and not the prototype. So in this.cVar + 1 it'll check the object instance to see if it has a cVar property. The first time increase is called, it doesn't. So JavaScript will look up the prototype chain until it finds it. So it finds 15. However, when it does the actual assignment back to this.cVar, it sets the property on the object instance itself and not the prototype (a shadowing of sorts).
So in your example,
console.log(a.cVar); // returns property from `a` itself
console.log(b.cVar); // returns property from the prototype
We can show this by using hasOwnProperty:
console.log( a.hasOwnProperty( "cVar" ) ); // true
console.log( b.hasOwnProperty( "cVar" ) ); // false
Objects do, in fact, share the prototype with one another as your research has lead you to believe. However, as go-oleg eluded to, there is a concept of the prototype chain. The prototype chain has a couple of behaviors you have to understand.
When you try to access a property on an object, it recursively looks up the chain starting from the object and looks for the property, then returns the value (This is what happens in the case of a read/get action).
When you try to set the value on a property on an object, it doesn't bother to recurse up the chain to find the property in the chain. Instead, if it doesn't find one on the object, it just adds the property along with the value you set on the object itself. This effectively hides the property that is higher up the prototype chain (This is what happens in the case of a write/set action).
If you placed your value inside an object then tried to set the value however, it would recurse to the object reference in a read attempt and since you have a reference pointer to the object, you would be setting the value on the object directly which would have the outcome you were expecting:
function TestObj(){
}
TestObj.prototype = {
cVar: 15,
obj: { val: 5 },
increase: function(){
this.cVar++;
},
objInc: function() {
this.obj.val++;
}
};
var a = new TestObj();
var b = new TestObj();
a.increase();
console.log(a.cVar);
console.log(b.cVar);
b.objInc();
console.log(a.obj.val);
console.log(b.obj.val);
//output
//16
//15
//6
//6
Hopefully that distinction clears up the confusion.
To be clear, "a" is an object, "b" is another, separate, object.
You then call the increase function only on "a", not "b". Therefore, unless I'm off my rocker,
It would make sense that b.cVar = 15, since it was never incremented.
Your getting confused by the terminology, and TestObject a is the only TestObject that you call increase() on. So it makes sense that a = 16 and b = 16, since you never call b.increase().
... that functions' prototype is shared between all the objects for that particular type.
That doesn't mean that each time any TestObject calls increase() then every other TestObject and itself also increase their cVar. Your thinking of something similar to the way that an EventListener and EventDispatcher system is set up. That function's prototype shared between all the objects for that particular type means that each TestObject instance has the prototype you defined.
The below code is taken from http://bonsaiden.github.com/JavaScript-Garden/
function Foo() {
this.value = 42;
}
Foo.prototype = {
method: function() {}
};
function Bar() {}
// Set Bar's prototype to a new instance of Foo
Bar.prototype = new Foo();
Bar.prototype.foo = 'Hello World';
// Make sure to list Bar as the actual constructor
Bar.prototype.constructor = Bar;
I have come across this explanation multiple times
"When accessing the property of an object, first it checks if the object its self has that property and if not than it goes to the prototype of that object to look for the property and so on."
But I am struggling to understand ho this actually works because of the behavior of the following code
var test1 = new Bar();
var test2 = new Bar();
test1.value = 24;
now value is not part of the test1 object but it is a property of its prototype which is a Foo Object, and since the prototype is a Foo Object all instances of Bar will share the value property, What i expect the above code to do is to set that value property to 24 but instead it creates a new property named 'value' to the test1 object and assigns it 24 leaving the value property in the prototype to its initial value 42. well this doesn't sound like sharing. test2.value still has a value of 42. when i look at the prototype chain in the firebug console it shows me that test1 has a value property with 24 and its prototype has a value property with 42.
This is very confusing to. Has any one you figured out why it behaves this way ?
The prototype chain is only used when reading properties and only if the property is not found in the object itself - it's not used when writing property values.
As soon as you write a property into an object (test1.value = 24) any existing "shared" property in the prototype with the same name is hidden, and all subsequent reads will access the value now store in the object itself.
I think you want .hasOwnProperty()
If that is what you are looking for, someone else has eloquently summed it up here
hasOwnProperty in javascript
EDIT
Having read the other answer, then properly read the questions this time... I'd like to retract that ;-)
...
Or maybe it is what you are looking for, it you want to check whether the property had been set on the 'hash' before doing something else.
I've read this too many times and confused I think, I'll shut up now
Just append the following lines at the end to check what's going on.
var test1 = new Bar();
test1.value = 30;
console.log(test1.hasOwnProperty("value"));
console.log(test1.value);
delete test1.value;
console.log(test1.hasOwnProperty("value"));
console.log(test1.value);
Output:
true
30
false
42
Terms:
hasOwnProperty only returns true is key is the local property of the object.
delete is used to delete local property it does not touch inherited properties.
Explanantion
If we assign a value then it creates it's own local property and overrides the prototypal property. And thus, as local properties has higher preference than prototypal properties, they are read first.