function classA(){};
classA.prototype.age =25;
var obj = new classA();
console.log(obj.age) //returns 25
Now, when I do:
classA.prototype = {};
Why obj.age is still returning 25?
This is happening because you pointed the classA.prototype to a new object but you didn't change the object that obj.prototype points to.
What is happening is:
classA.prototype ------> A
// create object with new classA()
// now its prototype also points to A
obj.prototype ------> A // points to the same prototype
now you reasign the prototype of classA
classA.prototype ------> B
but the prototype of obj still points to A (it was never changed)
obj.prototype ------> A
So all you did was change the prototype reference of classA after the prototype reference for obj was already established.
If you want to have obj see the changes on the prototype, then change the object it references (A in the example above) and not the reference itself:
Sample code:
function classA(){};
classA.prototype.age =25;
var obj = new classA();
console.log(obj.age) // 25
// change the object itself, not the reference
delete classA.prototype.age;
console.log(obj.age); // undefined
If your code is in the following order:
function classA(){};
classA.prototype.age = 25;
classA.prototype = {};
var obj = new classA();
console.log(obj.age) // returns undefined
The result will be indeed your excepted behavior. It depends on when you set the prototype of the classA function. This will be demonstrated by the following code snippet:
function classA(){};
classA.prototype.age = 25;
var obj1 = new classA();
classA.prototype = {};
var obj2 = new classA();
console.log(obj1.age) // returns 25
console.log(obj2.age) // returns undefined
Hence, a object is only affected by the changes to a prototype of a function, when this happens before the object's creation.
reassigning your prototype after creating the object has no effect on the previously created object , it will still have the old prototype when it was created. New prototye will only effect newly created objects
Related
I have this piece of code:
var MyConstructor = function(){};
var MyObject = new MyConstructor();
What I noticed is MyObject.constructor is not pointing to MyConstructor. So what is the standard way of accessing the constructor of an object from the object itself?
I need this to access constructor's prototype properties like MyConstructor.prototype = {mykey : "value"}. I can access mykey this way: MyConstructor.prototype.mykey but MyObject.constructor.prototype.mykey is not defined.
Here is the complete code and their output using jsconsole.com:
var MyConstructor = function(){};
MyConstructor.prototype = {mykey : "value"};
var MyObject = new MyConstructor();
MyObject.mykey; // output: "value"
MyConstructor.prototype.mykey; // output: "value"
MyObject.constructor.prototype.mykey; // output: undefined
MyObject.constructor === MyConstructor; // output: false
MyObject.constructor.prototype.mykey === "value"; // output: false
This happens because you change the prototype property of MyConstructor. That means that MyObject is created from that object and does not get the constructor property that the original prototype object had. So in your test case, MyObject.constructor === Object, since that is the constructor that is used for the object literal {mykey: "value"}.
To avoid this behaviour, don't assign a new object to the prototype property, but mutate the existing one:
var MyConstructor = function(){};
MyConstructor.prototype.mykey = "value";
var MyObject = new MyConstructor();
console.log(
MyObject.mykey, // output: "value"
MyConstructor.prototype.mykey, // output: "value"
MyObject.constructor.prototype.mykey, // output: "value"
MyObject.constructor === MyConstructor, // output: true
MyObject.constructor.prototype.mykey === "value", // output: true
);
Object.getPrototypeOf(MyObject).mykey gets the prototype directly from MyObject.
Mozilla developer link
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
Let's say I have the following code;
var A = {a:10};
var B = {b:20};
B.prototype = A;
alert(B.a);
I am getting undefined for B.a .
Am I doing something wrong? How do I set the prototype for object literal ?
I know how to do for Constructor object. So the following code works perfect
function A(){this.a=10}
function B(){this.b=20}
B.prototype = new A();
b = new B;
alert(b.a);
How do I do it for object literal ?
Objects inherit from their constructor's prototype property, not their own. The constructor's prototype is assigned to the internal [[Prototype]] property that is available in some browsers as the __proto__ property.
So for b to inherit from a, you need to put a on b's inheritance chain, e.g.
Classic prototype inheritance:
var a = {a: 'a'};
function B(){}
B.prototype = a;
var b = new B();
alert(b.a); // a
Using ES5 Object.create:
var a = {a: 'a'};
var b = Object.create(a);
alert(b.a); // a
Using Mozilla __proto__:
var a = {a: 'a'};
var b = {};
b.__proto__ = a;
alert(b.a); // a
The prototype property is usually present in a Function object. This prototype should be an object, and this object is used to define the properties of an object created with a constructor.
// Plain object, no prototype property here.
var plainObject = {one: 1, two: 2};
// Constructor, a prototype property will be created by default
var someConstruct = function() {
// Constructor property
someConstruct.constructProp = "Some value";
// Constructor's prototype method
someConstruct.prototype.hello = function() {
return "Hello world!";
}
};
// Another constructor's prototype method
someConstruct.prototype.usefulMethod = function() {
return "Useful string";
}
var someInstance = new someConstruct();
console.log(someInstance.hello()); // => Hello world!
console.log(someInstance.usefulMethod()); // => Useful string
console.log(someConstruct.constructProp); // => Some value
console.log(someConstruct.prototype); // => {usefulMethod: function, hello: function}
console.log(plainObject.prototype); // => undefined
So, plain objects have no prototypes.
Functions which work as constructors do have prototypes. These prototypes are used to fill an instance created with each construct.
Hope that helps :)
Only when using Function object that prototype is used, e.g. when you use a constructor. But no need of that for object literals.
Both of them are very good techniques, so it depends on what you want to do in a project and the JavaScript pattern you are using or like.
I have the following code (ObjA) and it works as I would expect, instance 'a1' has the same properties as 'a2' but with different values.
function ObjA() {
this.objLiteral = {};
this.propA = 0;
}
var a1 = new ObjA();
a1.objLiteral['hello'] = 3;
a1.propA = 1.5;
var a2 = new ObjA();
a2.objLiteral['goodbye'] = 4;
a2.propA = 2;
debugger info for a1 and a2:
http://www.flickr.com/photos/76617756#N02/6879283032/
Next, I have the following ObjB that inherits from ObjA. Instance 'b1' and 'b2' have the same properties and different values for properties propA and propB but for some reason, objLiteral is the same in both as if it was referencing the same object.
ObjB.prototype = new ObjA();
ObjB.prototype.constructor=ObjB;
function ObjB() {
this.propB = 2;
}
var b1 = new ObjB();
b1.objLiteral['hello2'] = 6;
b1.propA = 4;
b1.propB = 5;
var b2 = new ObjB();
b2.objLiteral['goodbye2'] = 8;
b2.propA = 6;
b2.propB = 7;
debugger info for b1 and b2:
http://www.flickr.com/photos/76617756#N02/6879283088/
Can somebody help me understand what is happening? What do I have to do to ge what I am expecting?
Your help is much appreciated.
Well, both objects b1 and b2 have the same prototype, namely an instance of ObjA:
ObjB.prototype = new ObjA();
hence they inherit and have access its properties. b1.objLiteral and b2.objLiteral refer to the same object:
and
> b1.objLiteral === b2.objLiteral
true
To fix that, you have to create a new object of each instance. This is normally done by calling the "parent" constructor inside the "child" constructor:
function ObjB() {
ObjA.call(this);
this.propB = 2;
}
ObjA.call(this) will call ObjA and within that function, this will refer to the argument passed to call [MDN], in this case the new instance of ObjB:
As you can see, objLiteral is now property of each instance:
> b1.objLiteral === b2.objLiteral
false
To avoid this confusion in the first place, setting an instance of the parent constructor as the prototype of the child constructor should be avoided. What if the parent constructor expects instance specific arguments? What would you pass to ObjA in this case?
It's better to set the prototype of the child constructor to the prototype of the parent constructor (with one level of indirection) and call the parent constructor like above:
function inherit(Child, Parent) {
var Tmp = function() {};
Tmp.prototype = Parent.prototype;
Child.prototype = new Tmp();
Child.prototype.constructor = Child;
}
inherit(ObjB, ObjA);
Tmp to prevent extending Parent.prototype if you extend Child.prototype later on.
Regarding propA:
It "works", because you are assigning a new value to it.
Here are again the objects, after assigning properties to x.objLiteral and x.propA. You can see that the objects don't have an own objLiteral property, but an own propA:
If instead you assign a new value to objLiteral, e.g. through
b1.objLiteral = {hello: 42};
b1 will now have its own property objLiteral, which shadows the inherited one:
I understand that there are two ways of creating classes in JavaScript
var MyObj = function(val)
{
this.vari = val;
}
Where val will be a non static member.
Whereas,
var MyObj = new Object();
MyObj.vari = "";
This is a single object so members of it here will act like static members. My question is that how do we have both static as well as non static content in same class?
There are no classes in JavaScript, only objects.
When you create a new object you are "extending" from the function's prototype, not the function itself. In order to make a variable or function appear to be static you would have to attach it to the function used to create the object, and not its prototype.
js> var Foo = function(){ this.member = "member"; };
js> Foo.staticMember = "staticMember";
js> var f = new Foo();
js> Foo.member;
undefined
js> Foo.staticMember;
"staticMember"
js> f.member;
"member"
js> f.staticMember;
undefined
Using your first example:
var MyObj = function(val) {
this.vari = val;
};
MyObj.var2=value;
Will create a new "static" property callable as:
var o = MyObj.var2;
The first one initializes the MyObj variable with the anonymous function - it does not create the class. The MyObj may be later used as the object constructor that initializes one object field - vari. There is nothing "statis" in OOP meaning.
The second one creates the object of the Object type and initializes its property. Again, there is nothing static.
In OOP "statis" means the member of the class, e.g. variables and objects that belong to class definition. For example, the following schema demonstrates this concept:
function MyClass() {
this.objectProperty = "I'm object property";
// the following demonstrates initialization of
// the object property from class (static) property:
this.varFromStatic = MyClass.classProperty;
}
MyClass.classProperty = "I'm class (static) property";
var obj = new MyClass();
// now obj.varFromStatic contains "I'm class (static) property"