Can someone explain why we have this behavior? I understand that it should act like this, but i can't explain
function foo() {}
function foo1() {}
foo.prototype = foo1.prototype = {};
var _foo = new foo();
alert( _foo instanceof foo1 ); // true
The instanceof operator checks to see if the left-hand operand is an object that has on its prototype chain the prototype object of the right-hand operand. Since both your functions share the same prototype object, an instance of one is considered an instance of the other.
In JavaScript, working with objects.
I think that is easier to understand if you compare this to more familiar objects
//defines a "class" Person
function Person() {}
//defines a "class" Animal
function Animal() {}
Change Animal and Person prototype
Person.prototype = Animal.prototype = {};
prototype could be used to extend "class", example
function Person(name){
this.name=name;
}
Person.prototype.nameInUperCase=function(){
return this.name.toUpperCase();
}
Instantiate
var myPerson = new Person();
Check if my person is instance of.
// true because you instantiate the same prototype
// remember Person.prototype = Animal.prototype = {};
alert(myPerson instanceof Animal);
o instanceof f checks to see if the object referenced by f.prototype appears anywhere in the prototype chain of o. In your case, since both foo.prototype and foo1.prototype refer to the same object, any object created via new foo or new foo1 will be instanceof both foo and foo1.
This is covered in the following sections of the spec: Runtime Semantics: InstanceofOperator(O, C), Function.prototype[##hasInstance] ( V ), and OrdinaryHasInstance (C, O), with most of the work being done in that last link, Steps 4 through 7 (7 has substeps for the loop through o's prototype chain).
Related
If we assume this sentence is true: "prototype is the object that is used to build __proto__", how Object.create works? If you do:
let obj1 = {
name: "obj1",
}
const obj2 = Object.create(obj1);
How Object.create() should create obj2.__proto__ from ob1.prototype when ob1.prototype is undefined??
Maybe Object.create() uses another method of creating prototypical inheritance than constructor or factory functions??
Because, in Object.create() example above this is true:
console.log(obj2.__proto__ === obj1);
but if we do the same thing with constructor function, this will be true:
console.log(obj2.__proto__ === obj1.prototype);
Constructing the object with the function:
function obj1(name) {
this.name = name;
}
const obj2 = new obj1();
Am I missing something?
Your sentence "prototype is the object that is used to build __proto__" only applies to functions that get called with new. E.g.
let dog = new Animal();
equals:
let dog = Object.create(Animal.prototype); // <<<
Animal.call(dog);
Prototypal inheritance itself just means that objects contain an "internal" (__proto__) reference to it's prototype. With Object.create you create an object whose prototype is set to the object passed. Therefore
let inherited = Object.create(obj)
is rather equal to
let inherited = {};
inherited.__proto__ = obj;
I've been trying to wrap my head around the new Object.create method which was introduced in ECMAScript 5.
Usually when I want to use inheritance I do something like this:
var Animal = function(name) { this.name = name; }
Animal.prototype.print = function() { console.log(this.name); }
var Dog = function()
{
return Animal.call(this, 'Dog');
}
Dog.prototype = new Animal();
Dog.prototype.bark = function() { console.log('bark'); }
I just assign a newly created Animal object to Dog's prototype and everything works like a charm:
var dog1 = new Dog();
dog1.print(); // prints 'Dog'
dog1.bark(); // prints 'bark'
dog1.name; //prints 'Dog'
but people(without explaining) are saying that Dog.prototype = new Animal(); is not the way inheritance works and that I should use Object.create approach:
Dog.prototype = Object.create(Animal.prototype);
which also works.
What's the benefit of using Object.create or am I missing something?
UPDATE: Some say that Dog.prototype = Animal.prototype; can also work. So now I'm totally confused
In the following I assume you are only interested in why Object.create is preferable for setting up inheritance.
To understand the benefits, lets first clarify what a "class" is made of in JavaScript. You have two parts:
The constructor function. This function contains all the logic to create an instance of the "class", i.e. instance specific code.
The prototype object. This is the object the instance inherits from. It contains all methods (and other properties) that should be shared among all instances.
Inheritance establishes an is-a relation, for example, a Dog is an Animal. How is this expressed in terms of constructor function and prototype object?
Obviously a dog must have the same methods as an animal, that is the Dog prototype object must somehow incorporate the methods from the Animal prototype object. There are multiple ways to do this. You will often see this:
Dog.prototype = new Animal();
This works because an Animal instance inherits from the Animal prototype object. But it also implies that every dog inherits from one specific Animal instance. That seems to be a bit strange. Shouldn't instance specific code only be run in the constructor function? Suddenly instance specific code and prototype methods seem to be mixed.
We don't actually want to run Animal instance specific code at that moment, we only want all the methods from the Animal prototype object. That is what Object.create lets us do:
Dog.prototype = Object.create(Animal.prototype);
Here we are not creating a new Animal instance, we only get the prototype methods. The instance specific code is executed exactly where it should be, inside the constructor:
function Dog() {
Animal.call(this, 'Dog');
}
The biggest advantage is that Object.create will always work. Using new Animal() only works if the constructor does not expect any arguments. Imagine if the constructor looked like this:
function Animal(name) {
this.name = name.toLowerCase();
}
You always have to pass a string to Animal, otherwise you will get an error. What will you pass when you do Dog.prototype = new Animal(??);? It doesn't actually matter which string you pass, as long as pass something, which hopefully shows you that this is bad design.
Some say that Dog.prototype = Animal.prototype; can also work. So now I'm totally confused
Everything that "adds" the properties from Animal.prototype to Dog.prototype will "work". But the solutions are of different quality. In this case here you will have the problem that any method you add to Dog.prototype will also be added to Animal.prototype.
Example:
Dog.prototype.bark = function() {
alert('bark');
};
Since Dog.prototype === Animal.prototype, all Animal instances have a method bark now, which is certainly not what you want.
Object.create (and even new Animal) add one level of indirection to the inheritance by creating a new object which inherits from Animal.prototype and that new object becomes Dog.prototype.
Inheritance in ES6
ES6 introduces a new syntax to create constructor functions and prototype methods, which looks like this:
class Dog extends Animal {
bark() {
alert('bark');
}
}
This is more convenient than what I explained above, but as it turns out, extends also uses an internal equivalent to Object.create to setup inheritance. See steps 2 and 3 in the ES6 draft.
Which means that using Object.create(SuperClass.prototype) is the "more correct" approach in ES5.
First, running the Animal constructor may have undesired side effects. Consider this:
var Animal = function(name) {
this.name = name;
Animal.instances.push(this);
};
Animal.instances = [];
This version would keep track of all instances that have been created. You don't want your Dog.prototype to be recorded there.
Second, Dog.prototype = Animal.prototype is a bad idea, since that would mean that bark would become a method of Animal.
I'm trying to illustrate the difference a little bit:
Here is what basically happens when you write new Animal():
//creating a new object
var res = {};
//setting the internal [[prototype]] property to the prototype of Animal
if (typeof Animal.prototype === "object" && Animal.prototype !== null) {
res.__proto__ = Animal.prototype;
}
//calling Animal with the new created object as this
var ret = Animal.apply(res, arguments);
//returning the result of the Animal call if it is an object
if (typeof ret === "object" && ret !== null) {
return ret;
}
//otherise return the new created object
return res;
And here is what basically happens with Object.create:
//creating a new object
var res = {};
//setting the internal [[prototype]] property to the prototype of Animal
if (typeof Animal.prototype !== "object") {
throw "....";
}
res.__proto__ = Animal.prototype;
//return the new created object
return res;
So it does the same but it doesn't call the Animal function and it also always returns the new created object.
In your case you end up with two different objects. With the first method you get:
Dog.prototype = {
name: undefined,
__proto__: Animal.prototype
};
and with the second method you get:
Dog.prototype = {
__proto__: Animal.prototype
};
You don't really need to have the name property in your prototype, because you already assigning it to your Dog instance with Animal.call(this, 'Dog');.
Your primary goal is to let your Dog instance access all the properties of the Animal prototype, which is achieved by both methods. The first method however does some extra stuff that is not really needed in your case or can even cause unwanted results as Pumbaa80 mentioned.
Let's understand it with code only;
A.prototype = B.prototype;
function B() {console.log("I am B");this.b1= 30;}
B.prototype.b2 = 40;
function A() {console.log("I am A");this.a1= 10;}
A.prototype.a2 = 20;
A.prototype = B.prototype;
A.prototype.constructor = A;
var a = new A;
var b = new B;
console.log(a);//A {a1: 10, b2: 40}
console.log(b);//B {b1: 30, b2: 40}
console.log(A.prototype.constructor);//A
console.log(B.prototype.constructor);//A
console.log(A.prototype);//A {b2: 40}
console.log(B.prototype);//A {b2: 40}
console.log(a.constructor === A); //true
console.log(b.constructor === A); //true
console.log(a.a2);//undefined
A.prototype = Object.create(B.prototype);
function B() {console.log("I am B");this.b1= 30;}
B.prototype.b2 = 40;
function A() {console.log("I am A");this.a1= 10;}
A.prototype.a2 = 20;
A.prototype = Object.create(B.prototype);
A.prototype.constructor = A;
var a = new A;
var b = new B;
console.log(a);//A {a1: 10, constructor: function, b2: 40}
console.log(b);//B {b1: 30, b2: 40}
console.log(A.prototype.constructor);//A
console.log(B.prototype.constructor);//B
console.log(A.prototype);//A {constructor: function, b2: 40}
console.log(B.prototype);//B {b2: 40}
console.log(a.constructor === A); //true
console.log(b.constructor === B); //true
console.log(a.a2);//undefined
I've learned that in a function's prototype, a pointer to the function itself is contained in a field called constructor.
function Person(){
}
alert(Person.prototype.constructor); // function Person(){}
If I overwrite the function's prototype with an object literal, the constructor field is naturally lost:
function Person(){
}
Person.prototype = {
name:"Sahand",
age:24
}
alert(Person.prototype.constructor); // function Object(){[native code]}
But, when the prototype has been overwritten in this manner, we can still check if an object is created by the Person constructor:
var person = new Person()
alert(person instanceof Person); // true
How is this possible? How can instanceof find out that person was created by Person() when the constructor field of the prototype doesn't contain Person anymore?
The instanceof operator tests whether an object in its prototype chain
has the prototype property of a constructor.
Consider this:
function Person(){}
Person.prototype = {
name:"Sahand",
age:24
}
var person = new Person();
console.log('instanceof', person instanceof Person);
console.log('Is "person __proto__ === Person.prototype":',
person.__proto__ === Person.prototype);
But if you change Person.prototype after instance creation then person instanceof Person === false now:
function Person(){}
Person.prototype = {
name:"Sahand",
age:24
}
var person = new Person();
Person.prototype = {};
console.log('insanceof: ', person instanceof Person);
Cause the instance instanceof constructor operator doesnt test instance.prototype.constructor but rather constructor.prototype in instance.__proto__
Reference
I've been trying to wrap my head around the new Object.create method which was introduced in ECMAScript 5.
Usually when I want to use inheritance I do something like this:
var Animal = function(name) { this.name = name; }
Animal.prototype.print = function() { console.log(this.name); }
var Dog = function()
{
return Animal.call(this, 'Dog');
}
Dog.prototype = new Animal();
Dog.prototype.bark = function() { console.log('bark'); }
I just assign a newly created Animal object to Dog's prototype and everything works like a charm:
var dog1 = new Dog();
dog1.print(); // prints 'Dog'
dog1.bark(); // prints 'bark'
dog1.name; //prints 'Dog'
but people(without explaining) are saying that Dog.prototype = new Animal(); is not the way inheritance works and that I should use Object.create approach:
Dog.prototype = Object.create(Animal.prototype);
which also works.
What's the benefit of using Object.create or am I missing something?
UPDATE: Some say that Dog.prototype = Animal.prototype; can also work. So now I'm totally confused
In the following I assume you are only interested in why Object.create is preferable for setting up inheritance.
To understand the benefits, lets first clarify what a "class" is made of in JavaScript. You have two parts:
The constructor function. This function contains all the logic to create an instance of the "class", i.e. instance specific code.
The prototype object. This is the object the instance inherits from. It contains all methods (and other properties) that should be shared among all instances.
Inheritance establishes an is-a relation, for example, a Dog is an Animal. How is this expressed in terms of constructor function and prototype object?
Obviously a dog must have the same methods as an animal, that is the Dog prototype object must somehow incorporate the methods from the Animal prototype object. There are multiple ways to do this. You will often see this:
Dog.prototype = new Animal();
This works because an Animal instance inherits from the Animal prototype object. But it also implies that every dog inherits from one specific Animal instance. That seems to be a bit strange. Shouldn't instance specific code only be run in the constructor function? Suddenly instance specific code and prototype methods seem to be mixed.
We don't actually want to run Animal instance specific code at that moment, we only want all the methods from the Animal prototype object. That is what Object.create lets us do:
Dog.prototype = Object.create(Animal.prototype);
Here we are not creating a new Animal instance, we only get the prototype methods. The instance specific code is executed exactly where it should be, inside the constructor:
function Dog() {
Animal.call(this, 'Dog');
}
The biggest advantage is that Object.create will always work. Using new Animal() only works if the constructor does not expect any arguments. Imagine if the constructor looked like this:
function Animal(name) {
this.name = name.toLowerCase();
}
You always have to pass a string to Animal, otherwise you will get an error. What will you pass when you do Dog.prototype = new Animal(??);? It doesn't actually matter which string you pass, as long as pass something, which hopefully shows you that this is bad design.
Some say that Dog.prototype = Animal.prototype; can also work. So now I'm totally confused
Everything that "adds" the properties from Animal.prototype to Dog.prototype will "work". But the solutions are of different quality. In this case here you will have the problem that any method you add to Dog.prototype will also be added to Animal.prototype.
Example:
Dog.prototype.bark = function() {
alert('bark');
};
Since Dog.prototype === Animal.prototype, all Animal instances have a method bark now, which is certainly not what you want.
Object.create (and even new Animal) add one level of indirection to the inheritance by creating a new object which inherits from Animal.prototype and that new object becomes Dog.prototype.
Inheritance in ES6
ES6 introduces a new syntax to create constructor functions and prototype methods, which looks like this:
class Dog extends Animal {
bark() {
alert('bark');
}
}
This is more convenient than what I explained above, but as it turns out, extends also uses an internal equivalent to Object.create to setup inheritance. See steps 2 and 3 in the ES6 draft.
Which means that using Object.create(SuperClass.prototype) is the "more correct" approach in ES5.
First, running the Animal constructor may have undesired side effects. Consider this:
var Animal = function(name) {
this.name = name;
Animal.instances.push(this);
};
Animal.instances = [];
This version would keep track of all instances that have been created. You don't want your Dog.prototype to be recorded there.
Second, Dog.prototype = Animal.prototype is a bad idea, since that would mean that bark would become a method of Animal.
I'm trying to illustrate the difference a little bit:
Here is what basically happens when you write new Animal():
//creating a new object
var res = {};
//setting the internal [[prototype]] property to the prototype of Animal
if (typeof Animal.prototype === "object" && Animal.prototype !== null) {
res.__proto__ = Animal.prototype;
}
//calling Animal with the new created object as this
var ret = Animal.apply(res, arguments);
//returning the result of the Animal call if it is an object
if (typeof ret === "object" && ret !== null) {
return ret;
}
//otherise return the new created object
return res;
And here is what basically happens with Object.create:
//creating a new object
var res = {};
//setting the internal [[prototype]] property to the prototype of Animal
if (typeof Animal.prototype !== "object") {
throw "....";
}
res.__proto__ = Animal.prototype;
//return the new created object
return res;
So it does the same but it doesn't call the Animal function and it also always returns the new created object.
In your case you end up with two different objects. With the first method you get:
Dog.prototype = {
name: undefined,
__proto__: Animal.prototype
};
and with the second method you get:
Dog.prototype = {
__proto__: Animal.prototype
};
You don't really need to have the name property in your prototype, because you already assigning it to your Dog instance with Animal.call(this, 'Dog');.
Your primary goal is to let your Dog instance access all the properties of the Animal prototype, which is achieved by both methods. The first method however does some extra stuff that is not really needed in your case or can even cause unwanted results as Pumbaa80 mentioned.
Let's understand it with code only;
A.prototype = B.prototype;
function B() {console.log("I am B");this.b1= 30;}
B.prototype.b2 = 40;
function A() {console.log("I am A");this.a1= 10;}
A.prototype.a2 = 20;
A.prototype = B.prototype;
A.prototype.constructor = A;
var a = new A;
var b = new B;
console.log(a);//A {a1: 10, b2: 40}
console.log(b);//B {b1: 30, b2: 40}
console.log(A.prototype.constructor);//A
console.log(B.prototype.constructor);//A
console.log(A.prototype);//A {b2: 40}
console.log(B.prototype);//A {b2: 40}
console.log(a.constructor === A); //true
console.log(b.constructor === A); //true
console.log(a.a2);//undefined
A.prototype = Object.create(B.prototype);
function B() {console.log("I am B");this.b1= 30;}
B.prototype.b2 = 40;
function A() {console.log("I am A");this.a1= 10;}
A.prototype.a2 = 20;
A.prototype = Object.create(B.prototype);
A.prototype.constructor = A;
var a = new A;
var b = new B;
console.log(a);//A {a1: 10, constructor: function, b2: 40}
console.log(b);//B {b1: 30, b2: 40}
console.log(A.prototype.constructor);//A
console.log(B.prototype.constructor);//B
console.log(A.prototype);//A {constructor: function, b2: 40}
console.log(B.prototype);//B {b2: 40}
console.log(a.constructor === A); //true
console.log(b.constructor === B); //true
console.log(a.a2);//undefined
If I can use obj.constructor.prototype to access the prototype of an object, then why can't I use obj.constructor.prototype.constructor.prototype to traverse the prototype chain and have to use Object.getPrototypeOf?
function MyConstructor()
{
this.prop = 1;
}
var o = new MyConstructor();
console.log(o.constructor.prototype) // MyConstructor
console.log(o.constructor.prototype.constructor.prototype) // MyConstructor?
Shouldn't it return the prototype of MyConstructor which is function() { [native code] } (in Chrome console)?
All constructors are instances of the global Function object:
function Foo(){ this.x = 1 }; // Dummy constructor function
console.log(Foo instanceof Function) // => true; Foo is an instance of global Function constructor
All prototypes are instances of the global Object object:
console.log(Foo.prototype instanceof Object); // => true
When a constructor Foo is defined, it automatically has a Foo.prototype object attached to it, which you can think of as a "blank" object that itself, as per the above, inherits from the global Object object. In other words, the prototype of Foo.prototype is Object.prototype:
function Foo(){ this.x = 1 }; // Dummy constructor function
console.log(Foo.prototype); // Foo (object); already exists
console.log(Object.getPrototypeOf(Foo.prototype) === Object.prototype); // => true
Since Foo.prototype is a blank object, one would expect its constructor to be the global Object constructor function:
function Foo(){ this.x = 1 }; // Dummy constructor function
console.log(Foo.prototype.constructor) // => function Foo() { this.x = 1; } ??
console.log(Foo.prototype.constructor === Object.prototype.constructor); // => false
However this "blank" object has an explicit self-referential constructor property that points back to function Foo(){ this.x = 1 } and overwrites or "masks" the default constructor property you are expecting:
function Foo(){ this.x = 1 }; // Dummy constructor function
delete Foo.prototype.constructor; // Delete explicit constructor property
console.log(Foo.prototype.constructor) // => function Object() { [native code] }
console.log(Foo.prototype.constructor === Object.prototype.constructor); // => true
Therefore you can't use obj.constructor.prototype recursively to traverse the prototype chain and have to rely on the Object.getPrototypeOf() method.
Here's a great visual reference.
If I can use obj.constructor.prototype to access the prototype of an object
You can't in general. Consider how this approach works:
var proto = MyConstructor.prototype;
// has an (nonenumberable) property "constructor"
proto.hasOwnProperty("constructor"); // `true`
// that points [back] to
proto.constructor; // `function MyConstructor() {…}`
As you see, that's a circular property structure. When you do
var o = new MyConstructor();
// and access
o.constructor; // `function MyConstructor() {…}`
// then it yields the value that is inherited from `proto`
// as `o` doesn't have that property itself:
o.hasOwnProperty("constructor"); // `false`
But that only works for object like o that inherit the constructor property from their prototype object and where that has a useful value with something pointing to the prototype object. Think of
var o = {};
o.constructor = {prototype: o};
Oops. Accessing o.constructor.prototype yields o itself here, and it could have been any other nonsensical value. The structure actually is the same as above with MyConstructor.prototype - and if you access proto.constructor.prototype.constructor.prototype[.constructor.prototype…] you won't get anything else than just proto.
then why can't I use obj.constructor.prototype.constructor.prototype to traverse the prototype chain and have to use Object.getPrototypeOf?
Because you're trapped in the circular structure as MyConstructor.prototype) has that constructor property itself and not inherited from Object.prototype. For really getting the next object the true prototype chain, you have to use Object.getPrototypeOf.
var o = new MyConstructor();
console.log(o.constructor.prototype) // MyConstructor
It should have been MyConstructor.prototype actually. Chrome console sometimes gets confused at displaying useful titles for unnamed objects though, and is not always correct.
If you get its prototype, it should yield Object.prototype, and when you get the prototype of the MyConstructor function itself it should be Function.prototype. Notice that you can do the latter by MyConstructor.constructor.prototype again…