I've always assumed that the prototype of a function was shared among all the objects, in a sense by reference. So if you change the value of a property of the prototype, all objects that share that prototype have the values change for them as well. So for instance below it seems that instead of the property bar being shared between all objects, it is copied. Is this right? Are the properties of the prototype of the constructor simply copied to all the class objects as they are created, or are they shared by linkage?
function foo()
{
this.bar = 1;
}
function derived() { }
derived.prototype = new foo()
object1 = new derived()
object2 = new derived()
object1.bar = 2;
//but notice if I had said here derived.prototype.bar = 3, object1.bar would still equal 2 but object2.bar would equal 3
alert(object2.bar) // this prints 1;
When you assign object1.bar = 2, you are creating an own property on object1, this property exist only in that object instance, and it has nothing to do with its prototype.
This property on object1 will shadow the value of the one existing on derived.prototype, this means that when you lookup object1.bar, it will find a value directly existing on that object.
On the other side, if you lookup object2.bar, this object doesn't have an own bar property, so the property lookup will search on the object this one inherits from (derived.prototype) and it will find the value 1.
Your object structure looks something like this:
object1
--------
| bar: 2 | -----------------
-------- | derived.prototype
| ----------
|------> | bar: 1 | -- foo.prototype
object2 (no own properties)| ---------- | ------------------
-------- | -> | constructor: foo |
| | ----------------- ------------------
-------- |
v
------------------
| Object.prototype |
------------------
|
v
null
Where the ---> lines denote the internal [[Prototype]] link that expresses inheritance.
For example, you have code:
function Animal() {
}
Animal.prototype.name="animal";
function Dog() {
}
Dog.prototype = new Animal
Dog.prototype.constructor=Dog;
Dog.prototype.name="dog";
object1 = new Animal();
object2 = new Dog();
As a result you have two object instances, that looked as (you can check this for example in Chrome devtools or FF firebug or...):
object1:
__proto__: (is ref into an Animal.prototype object)
constructor: function Animal()
name: "animal"
__proto__: Object (is ref into an Object.prototype object)
object2:
__proto__: (is ref into an Dog.prototype object)
constructor: function Dog()
name: "dog"
__proto__: (is ref into an Animal.prototype object)
constructor: function Animal()
name: "animal"
__proto__: (is ref into an Object.prototype object)
When you run next code (for example):
alert(object1.name); // displayed "animal"
alert(object2.name); // displayed "dog"
What happened? 1) Javascript looked for property name in object instance (in object1 or object2). 2) When not found, it looked up in object instance proto property (that is same as prototype of class function). 3) When not founct it looked in proto of proto and next and next while not found name property and others proto found. If as result of search property is found, then value is returned, if not found, then undefined returned.
What happened if you execute next code:
object2.name = "doggy";
As a result you have for object2:
object2:
name: "doggy"
__proto__: (is ref into an Dog.prototype object)
constructor: function Dog()
name: "dog"
__proto__: (is ref into an Animal.prototype object)
constructor: function Animal()
name: "animal"
__proto__: (is ref into an Object.prototype object)
Property is assigned directly into instance object, but prototype object remains unchanged. And when you execute:
alert(object1.name); // displayed "animal"
alert(object2.name); // displayed "doggy"
When you need to create|change shared property of class, you can use one from next algoritms:
1)
Animal.prototype.secondName="aaa";
alert(object1.secondName); // displayed "aaa"
alert(object2.secondName); // displayed "aaa"
Animal.prototype.secondName="bbb";
alert(object1.secondName); // displayed "bbb"
alert(object2.secondName); // displayed "bbb"
// but
Animal.prototype.secondName="ccc";
object1.secondName="ddd";
alert(object1.secondName); // displayed "ccc"
alert(object2.secondName); // displayed "ddd"
2)
Create property of type object in prototype of function class and assign values to properties of this object.
Animal.prototype.propObject={thirdName:"zzz"};
alert(object1.propObject.thirdName); // displayed "zzz"
alert(object2.propObject.thirdName); // displayed "zzz"
Animal.prototype.propObject.thirdName="yyy";
alert(object1.propObject.thirdName); // displayed "yyy"
alert(object2.propObject.thirdName); // displayed "yyy"
object1.propObject.thirdName="xxx";
alert(object1.propObject.thirdName); // displayed "xxx"
alert(object2.propObject.thirdName); // displayed "xxx"
object2.propObject.thirdName="www";
alert(object1.propObject.thirdName); // displayed "www"
alert(object2.propObject.thirdName); // displayed "www"
Related
Why can't I assign new properties to non-frozen object, which has frozen prototype:
Working without Object.freeze:
'use strict'
//This object will be prototype of next objects
var defaults = {
name: 'def name',
sections: {
1: {
secName: 'def sec name'
}
}
};
//So we have an empty object with prototype set to our default object.
var specificObject = Object.create(defaults);
specificObject.sections = {};
console.log(specificObject.hasOwnProperty('sections')); //true
specificObject.sections['1'] = Object.create(defaults.sections['1']);
Above code works as expected, but I want to make sure that defaults won't be accidentally changed. So I want to freeze my defaults object:
'use strict'
//This object will be prototype of next objects
var defaults = {
name: 'def name',
sections: {
1: {
secName: 'def sec name'
}
}
};
//!!!!!!!!!!!!
Object.freeze(defaults);
//So we have an empty object with prototype set to our default object.
var specificObject = Object.create(defaults);
//TypeError: Cannot assign to read only property 'sections' of #<Object>
specificObject.sections = {};
console.log(specificObject.hasOwnProperty('sections')); //true
specificObject.sections['1'] = Object.create(defaults.sections['1']);
What I don't get is why can't I assign to specificObject if its prototype is frozen?
//EDIT:
Notice that specific object is not frozen:
'use strict'
//This object will be prototype of next objects
var protoObj = {a: 1, o: {}};
Object.freeze(protoObj);
console.log(Object.isFrozen(protoObj)); //true
var n = Object.create(protoObj);
console.log(Object.isFrozen(n)); //false
What I don't get is why can't I assign to specificObject if its prototype is frozen?
Because property attributes are inherited. Yes, it's odd.
If you freeze an object, it will set the [[writable]] attribute of all data properties to false.
If you assign to an object property, but that property does not exist on the object, it will go and look it up on the prototype - it might be defined as setter there. When this lookup will return and say that there is a property of that name but it is non-writable, your assignment will fail (and throw in strict mode).
What can you do against this?
Use Object.defineProperty instead of assignment, it doesn't check the prototype
or similarly, use the second parameter of Object.create to create the own property
freeze the defaults only after you've assigned to specificObject.
my understanding is that specificObject.sections is pointing to its' prototype which is defaults and it is frozen object. You define a new object {} but you try to assign it to defaults.sections. SpecificObject.sections is pointing exactly there.
If you create new ownProperty on specificObject it will work:
'use strict'
//This object will be prototype of next objects
var defaults = {
name: 'def name',
sections: {
1: {
secName: 'def sec name'
}
}
};
//!!!!!!!!!!!!
Object.freeze(defaults);
//So we have an empty object with prototype set to our default object.
var specificObject = Object.create(defaults);
// this will create new property
Object.defineProperty(specificObject, 'sections',{
enumerable: true,
writable: true,
configurable: true,
value: {}
});
console.log(specificObject.hasOwnProperty('sections')); //true
specificObject.sections['1'] = Object.create(defaults.sections['1']);
explanation:
if you try to access obj.prop = val then javascript looks into obj's own properties, if not found then it looks into obj's prototype own properties. if found there then it /tries to assign val to/ lookup that property. if not found there then it tries to look into obj's prototype's prototype and so on. If prop is not found in the prototype tree then it creates new own property on obj and assigns val.
Therefore if prop is find on prototype and it is frozen you will get type error. Hope it brings some light.:)
EDIT:
as correctly pointed out by #KubaWyrostek specificObj.sections = {} will create new own property of specific Object, does not assign new value to the prototype's property, but it probably does the lookup for the property to check the writability, in that case it will run into frozen object. I didn't know about this before.
Is prototype inheritance behaving differently based on the type? Is the contextual reference THIS working different in these two cases? Why in this examples, one is accessing to the prototype and the other one is creating a new property to the object?
var Player = function(){};
Player.prototype.name = '';
Player.prototype.set_name = function(name){this.name = name;}
var p1 = new Player();
var p2 = new Player();
p1.set_name('Johanna');
Value return by these two:
// Checking object properties
>p1
Player {name: "Johanna", set_name: function}
>p2
Player {name: "", set_name: function}
// Checking prototypes
>p1.__proto__
Object {name: "", set_name: function}
>p2.__proto__
Object {name: "", set_name: function}
But if I do the Player with name as an object property, the function set_name is modifying the prototype.
var Player = function(){};
Player.prototype.name = {};
Player.prototype.set_name = function(name){this.name['first_name'] = name;}
var p1 = new Player();
var p2 = new Player();
p1.set_name('Andrew');
Value return by these two:
// Checking object properties
>p1.name
Object {first_name: "Andrew"}
>p2.name
Object {first_name: "Andrew"}
// Checking prototypes
>p1.__proto__.name
Object {first_name: "Andrew"}
>p2.__proto__.name
Object {first_name: "Andrew"}
Why is this happening? What concept(s) am I missing?
Inheritance chain
When you create an object with a constructor function, the inheritance chain goes like this, for lookup.
The current object will be searched.
Prototype of the parent will be searched.
Prototype of the parent's parent will be searched.
...
And finally the global object will be searched. If it is not found anywhere, undefined will be returned. If the value being looked up is found in any of these levels, it will be returned immediately.
Note: Assignments won't go up the inheritance chain. If you assign a value to an attribute of an object (if it is not present it will be created) then the value will be assigned to that attribute.
First case:
You are doing
this.name = name;
So,
p1.set_name('Andrew');
creates a new name attribute in p1 and stores Andrew in it. And when you tried to print p1, the name was looked up on p1 and it was found in p1 itself. So, Andrew was returned. But, when you printed p2, name is not found in p2. It goes up in the hierarchy and finds the name in parent's prototype. So, it returns the empty string.
Second case:
You are doing
this.name['first_name'] = name;
So,
p1.set_name('Andrew');
looks up name in p1. Because you are trying to access 'first_name' on this.name. So, it tries to retrieve name attribute. It doesn't find it in p1, so goes up and finds it in the parent's prototype. It is an empty object and name gets assigned to first_name attribute of that object.
We know that p2's prototype is the same as p1's prototype. We can confirm that like this
console.log(p1.__proto__ === p2.__proto__);
# true
So, when you look up p2's prototype, which is the same as p1's prototype, the name Andrew is found.
As a general case variables and such are set in the constructor.
For more info on the subject and a better explanation than i can do reference here: http://javascriptweblog.wordpress.com/2010/06/07/understanding-javascript-prototypes/
// Constructor
function Player() {
this.names = '';
};
// Public Method
Player.prototype.set_name = function(name){
this.name = name;
}
// Static method
Player.walk = function() {}
var player1 = new Player();
player1.set_name('John Doe'); // fires the public method
Player.walk(); // fires the static method
reading the What techniques can be used to define a class in JavaScript, and what are their trade-offs? on stackoverflow i understand that i can define a class via
Method 1:
function Person(name, gender){
this.name = name;
this.gender = gender;
}
and add functions in prototype so as to avoid member functions recreated every time its instantiated. like
Person.prototype.speak = function(){
alert("my name is" + this.name);
}
and create its instances via
var person = new Person("Bob", "M");
I think the creation of same object is possible with out new keyword like
Method 2:
var Person = function (name, gender) {
return {name:name, gender:gender};
}
person = Person("Bob", "M");
Is the second method doing exactly the same thing done by the first one? Also if so how would i mock up addition of functions via prototype (as we see in method 1's speak) in the second approach?
No, Method 2 != Method 1. The second method is creating a new anonymous object with a prototype that points at Object.prototype while the first is creating a new object with a prototype that points at Person.prototype.
In psuedo-code:
// Method #1
function Person(name, gender) {
// The magic JS does *for us* (but *only* when invoked with `new`)
var this = {};
// __proto__ is the *internal* prototype reference
// It's not required to be accessible unless you're in an ES6 environment.
this.__proto__ = Person.prototype;
// Person.prototype is also created by JS for us
// and provided with a reference (among other things)
// to this function as prototype.constructor.
// Our stuff
this.name = name;
this.gender = gender;
// More JS magic
return this;
}
// Method #2
function Person(name, gender) {
// Just our stuff - no magic JS goodness here
return {
name: name, gender: gender
};
}
As Sean Vieira explained the first method is not the same as the second method. In the first method the instance inherits from Person.prototype. In the second method the instance inherits directly from Object.prototype.
Method 1:
null
^
|
| __proto__
|
+------------------+
| Object.prototype |
+------------------+
^
|
| __proto__
|
+------------------+
| Person.prototype |
+------------------+
^
|
| __proto__
|
+------------------+
| person |
+------------------+
Method 2:
null
^
|
| __proto__
|
+------------------+
| Object.prototype |
+------------------+
^
|
| __proto__
|
+------------------+
| person |
+------------------+
Interestingly the above diagrams show you that objects inherit from other objects in JavaScript, and not from constructors. Hence when you create new Person the instance inherits from Person.prototype, not from Person itself.
How is this relevant information? For starters it demonstrates that you don't need to create a constructor to creates instances of an object. Instead you directly create the prototype object as follows:
var person = {
create: function (name, gender) {
var person = Object.create(this);
person.gender = gender;
person.name = name;
return person;
},
speak: function () {
alert("My name is " + this.name + ".");
}
};
In the above example person is equivalent to Person.prototype. You may now create an instance of person as follows:
var bob = person.create("Bob", "M");
The prototype chain of bob will look like this:
null
^
|
| __proto__
|
+------------------+
| Object.prototype |
+------------------+
^
|
| __proto__
|
+------------------+
| person |
+------------------+
^
|
| __proto__
|
+------------------+
| bob |
+------------------+
So why should you create objects like this instead?
It looks cleaner. Everything is encapsulated in a single object literal.
It's easier to understand that objects inherit from objects. No constructors needed.
You don't need to use new to create an instance. This solves a lot of problems.
For more information about this pattern read my blog post on "Why Prototypal Inheritance Matters".
Your examples are achieving the same thing with regards to accessing the properties, but they are not identical as the first method has the basic Object prototype. The answer to your second question is:
function Person( name, gender ){
return {
name: name,
gender: gender,
speak: function(){
alert("my name is" + this.name);
}
};
}
Here there is no prototype. The function is baked into the object literal. The only value in using a literal instead of a prototype would be to create a closure so you can have private variables e.g:
function Person( name, gender ){
return {
speak: function(){
alert("my name is" + name);
}
};
}
Maybe this answer can explain a bit more about constructor functions, inheritance, private variables and overriding methods: Prototypical inheritance - writing up
The other answers already address your question; creating an object as an object literal {prop:val,method:function(){}} and creating an object using constructor functions: var MyObject=function(){this.prop=val};MyObject.prototype.method=function(){};
I have read a lot on how prototypal inheritance works and how the interpreter travels the prototype chain to find the property.
function Man()
{
this.hands=2;//1
}
function father()
{
this.name="";
}
father.prototype= new Man();//2
var malay= new father();
var abhik= new father();
Now my question is that statement #1 & #2 is only invoked once . So "abhik" and "malay" should both share the same Man object ?
So there will be 3 objects in memory .
1.abhik
2.malay
3.man (One instance shared by both)
So by that logic the changed value should be shared across objects ?
malay.hands=3;
console.log(abhik.hands);
abhik.hands=4;
console.log(malay.hands);
But it is not the case.
Why so ?
Your understanding is correct that there are 3 objects and both abhik and malay inherit from the same Man instance. But when you set new hands properties on the malay and abhik objects, you give them their own hands property and they are no longer inheriting the hands property from the prototype Man.
Illustration:
After you first create malay and abhik, here is a mock of your three objects:
father.prototype -> {hands: 2}
malay -> {name: ""} // Empty name property, NO hands property
abhik -> {name: ""} // Empty name property, NO hands property
When you check for the hands property on malay or abhik, the interpreter will see that there is no such property and will check up the prototype chain and will find that their parent father.prototype does have a hands property, so the interpreter will report that value, which is 2.
After you set the hands properties, your objects look like this:
father.prototype -> {hands: 2}
malay -> {name: "", hands: 3} // Empty name property, OWN hands property
abhik -> {name: "", hands: 4} // Empty name property, OWN hands property
Now your objects all have their own hands properties.
Resource: Here is a very well-written (but long) article about javascript inheritance:
http://manuel.kiessling.net/2012/03/23/object-orientation-and-inheritance-in-javascript-a-comprehensive-explanation/
If you need to share a primitive type or immutable among instances you can use closures to retain it's value and use getters and setters to access it.
function Man()
{
var hands=2;
return {
getHands:function(){
return hands;
},
setHands:function(number){
hands=number;
}
}
}
function Father(name)
{
this.name=name;
}
Father.prototype= Man();
malay=new Father("malay");
abhik=new Father("abhik");
malay.setHands(4);
console.log(abhik.getHands());
console.log(malay.getHands());
If you need Father to be an instance of Man you can do the following:
function Hands(){
var hands=2;
return {
get:function(){
return hands;
},
set:function(number){
hands=number;
}
}
}
function Man(){
this.age=18;
this.array=[];
}
Man.prototype.hands=Hands();
function Father(name){
//take ownership (copy) of every variable
//defined in the Man function body
//with this.... prototype defined
//are still shared among instances
Man.call(this);
this.name=name;
}
Father.prototype= new Man();
malay=new Father("malay");
abhik=new Father("abhik");
malay.hands.set(4);
console.log(abhik.hands.get());
console.log(malay.hands.get());
malay.age=34;
console.log(abhik.age);//from Man.age
console.log(malay.age);//from malay.age
delete malay.age;
console.log(malay.age);//from Man.age
malay.array.push(22);
console.log(abhik.array);// is [] but would be [22]
// if Man.call(this) was not in the Father function
console.log(malay instanceof Man);
Why is that this code:
var foo = {one: 1, two: 2};
var bar = new Object( foo );
bar.three = 3;
bar.one = 100;
document.write(bar.one); //100
document.write(foo.one); //100
results in bar.one & foo.one being both 100, while
var foo = {one: 1, two: 2};
var bar = Object.create( foo );
bar.three = 3;
bar.one = 100;
document.write(bar.one); //100
document.write(foo.one); //1
only affects bar.one..
My first intuition is that since in the first piece of code we are assigning a foo reference to bar, then it means the change will also apply to foo, while on the second code, it probably 'inherits' from foo, and therefore the change on bar's 'subclass' attribute won;t apply to its 'superclass' (prototype)..
Can somebody please confirm that my assumption is at least on the right track? Would absolutely appreciate any answers. Thanks in advance.
The line:
var bar = new Object( foo );
In your first snippet, it doesn't do anything -you are right with your assumption-, it will simply return a reference to the same object passed to the Object constructor.
That's the behavior when you pass a native object to the Object constructor in a new expression (new Object(value)), if you pass a host object, the results are implementation dependent.
If you don't pass a value (or you explicitly pass the primitives undefined or null) a new object that inherits from Object.prototype will be created.
Otherwise, if you pass any of the remaining primitives (as a Number, String or a Boolean value), a primitive wrapper object will be created (basically "primitive-to-object" type conversion), for example.
var s = new String("foo"); // a string object wrapper
typeof s; // "object"
s.valueOf(); // "foo"
See this question about primitives and objects: How is a Javascript string not an object?
In your second snippet, the line:
var bar = Object.create( foo );
Creates a new object, that inherits from foo, and since it's a different object, when you assign the properties:
bar.three = 3;
bar.one = 100;
Those will be created physically on that separated instance, as you can see, the bar.one property shadows the value contained in foo.
The object referenced by bar, in fact will contain two own properties (one and three, but since it inherits from foo, the property named two is resolvable through the prototype chain, for example:
bar.hasOwnProperty('one'); // true, the property is "own"
bar.hasOwnProperty('two'); // false, the property is "inherited" from foo
bar.two; // 2, is accessible
Basically, the prototype chain of bar looks like this:
-----------------
========> | Object.prototype| ==> null
| -----------------
|-------------| [[Prototype]] |---------|
| one: 100 | ====================> | one: 1 | (shadowed)
| three: 3 | | two: 2 |
|-------------| |---------|
(== line denotes the prototype chain)
new Object and Object.create do completely different things, despite their similar sounding names.
new Object(), with no argument, is equivalent to an empty object literal {}, which you should always use instead. With an argument, new Object(obj) simply returns the argument.
Object.create(obj) helps untangle JavaScript's messed up prototypal inheritance. Reading this article by Douglas Crockford will help with that. Basically, it creates a new object that inherits from obj. So if you have
var obj1 = {x: 1}, obj2 = Object.create(obj1);
obj1.x; // 1
obj2.x; // 1
obj2.x = 42;
obj1.x; // 1
obj1.x = 10;
obj2.x; // 10, since obj2 inherits from obj1, changing obj1's properties
// changes obj2, but not the other way around.