Javascript prototype chain behaves unexpectedly - javascript

Here is my code:
var Person = new Function() // same as function Person(){}
var john = new Person()
now I have prototype chain like that: Object -> Function -> Person -> john
Now I am doing something like that:
Function.prototype.bar = "boo"
So I expect to have Person.bar and john.bar to be "boo"
Person.bar // boo
john.bar // undefined
so what happened? I dived into and found out that john.__proto__ is prototype of Person, but john.__proto__.__proto__ is NOT prototype of Function, it's prototype of Object, so I lost one piece of chain(Finction). that's why john.bar was undefined. So why is this happening? shouldn't I be able to access Function prototype properties from john?

When you have
var Person = new Function()
you get an empty function which does nothing and returns nothing, eg
function Person() {
}
When you create an instance of Person with new, the newly created object will look at Person.prototype, and since Person.prototype inherits from Object (not Function), you won't see the .bar property.
function Person() {
}
const john = new Person();
console.log(
Object.getPrototypeOf(john) === Person.prototype,
Object.getPrototypeOf(Person.prototype) === Object.prototype
);
It's really weird to try to create an instance of a function, but if you wanted to, I suppose you could get what you're looking for by having Person return a Function instance:
Function.prototype.bar = "boo"
function Person() {
return new Function();
};
const john = new Person();
console.log(john.bar);
I'd highly recommend not trying to create Function instances like this, though.
If you want an (odd) inheritance chain of
Object -> Function -> Person -> john
then you can use Object.create:
//const Person = Object.create(Function);
// or
const Person = new Function();
const john = Object.create(Person);
Function.prototype.foo = 'foo';
console.log(john.foo);

Consider the following image taken from this answer.
As you can see, when you create a function in JavaScript a new prototype object is automatically created as well.
function Person() {}
Hence, the above code is actually:
function Person() {}
Person.prototype = { constructor: Person };
Now, you should also understand that the __proto__ property of a function is different from its prototype property.
function Person() {}
console.log(Person.__proto__ === Function.prototype); // true
console.log(Person.prototype !== Function.prototype); // true
When you create an instance of Person using the new keyword, that instance object inherits from Person.prototype and not from Person or Person.__proto__:
function Person() {}
const john = new Person;
console.log(john.__proto__ !== Person); // true
console.log(john.__proto__ !== Person.__proto__); // true
console.log(john.__proto__ === Person.prototype); // true
The same goes for functions created by calling new Function.
const Person = new Function;
console.log(Person.__proto__ === Function.prototype); // true
console.log(Person.prototype !== Function.prototype); // true
That's the reason why john does not inherit from Function.prototype. The prototype chain for john is as follows.
__proto__ __proto__ __proto__
john -----------> Person.prototype -----------> Object.prototype -----------> null
Whereas the prototype chain of Person is as follows:
__proto__ __proto__ __proto__
Person -----------> Function.prototype -----------> Object.prototype -----------> null
Here's the proof:
const Person = new Function;
const john = new Person;
console.log(john.__proto__ === Person.prototype); // true
console.log(john.__proto__.__proto__ === Object.prototype); // true
console.log(john.__proto__.__proto__.__proto__ === null); // true
console.log(Person.__proto__ === Function.prototype); // true
console.log(Person.__proto__.__proto__ === Object.prototype); // true
console.log(Person.__proto__.__proto__.__proto__ === null); // true
This is because Person.prototype !== Person.__proto__.
Now, you may ask why do we have both the prototype and the __proto__ properties. The reason for this is because an object in JavaScript (let's call it derived) inherits from another object (let's call it base) if and only if derived.__proto__ = base. Consider the following code:
const base = { foo: 10 };
const derived = {};
derived.__proto__ = base; // derived now inherits from base
console.log(derived.foo); // 10
const newBase = { bar: 20 };
derived.__proto__ = newBase; // derived no longer inherits from base, it inherits from newBase
console.log(derived.foo); // undefined
console.log(derived.bar); // 20
Now, when you create an instance of a function the instance actually inherits from the prototype of the function. It doesn't inherit from the function.
function Person() {}
const john = new Person;
The above code is equivalent to:
function Person() {}
Person.prototype = { constructor: Person };
const john = { __proto__: Person.prototype };
Person.call(john);
Hope that clears things.

Related

What is the prototype chain for a function constructor?

I have been learning about the prototype chain from a tutorial and am confused by the prototype chain for a function constructor.
Here is my constructor function with a prototype and a new instance:
let Fun2 = function(name) {
this.name = name
}
Fun2.prototype.who = () => console.log('who')
const name = new Fun2('bill')
then as I expect, the __proto__ property of the name instance is the Fun2 prototype, however the prototype property of Fun2 points to the Object prototype:
name.__proto__.__proto__
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
I also learned that a functions prototype chain goes up to a general function.prototype (the same as an array has an array.prototype), since Fun2 is a function, why doesn't it point to the function.prototype and then point to the Object.prototype, I don't understand why it is skipping this step, can someone clarify this please.
The thing that can be confusing is that the prototype property (of a constructor) gives the prototype for objects that the function will construct, while the __proto__ property of the constructor refers to the prototype used for creating the constructor. These are unrelated prototypes: the constructor has a prototype chain that has nothing to do with the prototype chain of an object that is constructed with that constructor.
why doesn't it point to the function.prototype and then point to the Object.prototype
It does that. Object.getPrototypeOf(Function.prototype) is Object.prototype.
Look at these results:
const Fun2 = function(name) {}
const name = new Fun2('bill');
console.log(
"Test prototype chain of the constructed object:",
Object.getPrototypeOf(name) === Fun2.prototype, // true
// ↓
Object.getPrototypeOf(Fun2.prototype) === Object.prototype, // true
);
console.log(
"Test prototype chain of the constructor:",
Object.getPrototypeOf(Fun2) === Function.prototype, // true
// ↓
Object.getPrototypeOf(Function.prototype) === Object.prototype, // true
);
See also How does JavaScript .prototype work? and, if you wish, my answer in that collection of answers.
function myFunction() {}
myFunction.prototype.Test = function () {};
console.log(myFunction.__proto__ === Function.prototype); //True
console.log(myFunction.constructor === Function.prototype.constructor); //True
console.log(myFunction.prototype.constructor === myFunction); //True
In case if you are creating the object using the new operator
let obj1 = new myFunction();
console.log(obj1.__proto__ === myFunction.prototype); //True
let obj2 = Object.create(myFunction.prototype);
console.log(obj2.__proto__ === myFunction.prototype); //True

Fix for constructor property in protypical inheritence

The book "JavaScript for Ninja" suggested the following fix for constructor property while establishing prototypical chain between objects:
If I create a Person object as follow:
var person = new Person();
alert(person.constructor == Ninja); // Display true
Even though its fix the problem that ninja.constructor will refer to the Ninja function, But it creates the another problem that now person.constructor will also refer to the Ninja function instead of Person.
Reproducible Example:
function Person() {
}
var person = new Person();
Person.prototype.dance = function() {};
function Ninja() {
}
Ninja.prototype = person;
Object.defineProperty(Ninja.prototype, "constructor", {
enumerable: false,
value: Ninja,
writable: true
})
var ninja = new Ninja();
alert(person.constructor == Ninja); // Display true
I am unable to understand why this fix was suggested by the author.
You're only modifying the constructor property of that one person instance, not the whole Person class. If you do
person2 = new Person();
console.log(person2.constructor == Ninja);
it will print false.
Notice that in the book you quoted, it didn't even assign the new Person() object to a variable, it just created an anonymous object for use in creating the prototype chain.
In general, the object used in the prototype chain will not usually be used as an actual object in the application, it just serves the purpose of linking the related classes.
function Person() {
}
var person = new Person();
Person.prototype.dance = function() {};
function Ninja() {
}
Ninja.prototype = person;
Object.defineProperty(Ninja.prototype, "constructor", {
enumerable: false,
value: Ninja,
writable: true
})
var ninja = new Ninja();
var person2 = new Person();
console.log(person.constructor == Ninja);
console.log(person2.constructor == Ninja);

What is the difference let o1.prototype = Object.create(o2.prototype) and o1.prototype = o2.prototype? [duplicate]

This question already has answers here:
Why wouldn't I use Child.prototype = Parent.Prototype rather than Child.prototype = new Parent(); for Javascript inheritance?
(3 answers)
Benefits of using `Object.create` for inheritance
(4 answers)
Closed 3 years ago.
So I'm trying to understand the difference between o1.prototype = Object.create(o2.prototype) and o1.prototype = o2.prototype.
According to the answer to this question, the former sets obj2.prototype to by the prototype for obj1.prototype, but I'm having a hard time grasping why you would want that (the prototype of a new prototype for example is just Object.prototype since the prototype IS an Object without further inheritance). Furthermore, it doesn't seem to quite work the way the answer to that question suggests all the time.
In the following code, for example:
function o1(){}
o1.prototype.test = "test";
function o2(){}
o2.prototype = Object.create(o1.prototype);
let instance1 = Object.create(o1);
console.log(o2.prototype.test, instance1.prototype.test);
both o2.prototype.test and instance1.prototype.test print "test". So it doesn't seem to matter weather you assign the o2 directly to Object.create(o1.prototype) or set the o2's prototype to Object.create(o1.prototype).
Also, if I'm understanding this correctly, according to the answer in the linked question, if o1 is empty (which is it in this case) then setting o2 = o1 would be the same as setting setting o2 = Object.create(o1) which would also be the same as
function o1(){};
function o2(){};
o2.prototype = o1.prototype;
Is there any significant difference between those three? Also, if o2.prototype = Object.create(o1.prototype) creates an empty object with o1.prototype's prototype as it's own prototype, if o1's prototype is not empty, then how do the members of o1's prototype get imported into o2's prototype?
If you directly assign Parent.prototype to a child's prototype, they'll both be pointing to the same object. So, if you add a method, which only applies to the child class, Parent objects will also have access to them because Parent.prototype === Child.prototype
Example:
function Animal() {};
Animal.prototype.Eat = function() {
console.log("Eating")
}
function Human() {};
Human.prototype = Animal.prototype; // both point to the same object
Human.prototype.Drive = function() {
console.log("Driving")
}
var animal = new Animal();
var human = new Human();
animal.Eat();
human.Eat();
animal.Drive(); // Animals shouldn't be driving
human.Drive();
console.log("animal instanceof Human: ", animal instanceof Human) // true
If you use Object.create(Animal.prototype) instead, it creates a new object with the [[Prototype]] (also, but deprecated, __proto__) set to Anima.prototype. So, if any methods are not found on Human.prototype, it will fall back to Animal.prototype (In this case Eat)
function Animal() {};
Animal.prototype.Eat = function() {
console.log("Eating")
}
function Human() {};
Human.prototype = Object.create(Animal.prototype)
Human.prototype.constructor = Human; // update the constrcutor
Human.prototype.Drive = function() {
console.log("Driving")
}
var animal = new Animal;
var human = new Human;
animal.Eat();
human.Eat();
human.Drive();
try {
// This will throw an error because Animal.prototype doesn't have a Drive method
animal.Drive();
} catch {
console.log("Animals can't drive")
}
console.log("animal instanceof Animal: ", animal instanceof Animal) // true
console.log("animal instanceof Human: ", animal instanceof Human) // false
console.log("human instanceof Animal: ", human instanceof Animal) // true
console.log("human instanceof Human: ", human instanceof Human) // true
console.log(animal.constructor)
console.log(human.constructor)
When you access, human.Eat(), first the method will looked up directly under the human object. If not found, this will be searched in its prototype which is Human.prototype.
Object.getPrototypeOf(human) === Human.prototype;
Since, Eat method is not found there, the method will be looked inside the prototype of Human.prototype which is Animal.prototype
Object.getPrototypeOf(Human.prototype) === Animal.prototype
The method is found here and it will be executed.
Let's say you want to use human.hasOwnProperty('eyes'). It goes through the similar chain as above. If hasOwnProperty is not found on human object, Human.prototype or Animal.prototype, it will check inside Object.prototpye because
Object.getPrototypeOf(Animal.prototype) === Object.prototype
Object.prototype has a method called hasOwnProperty and that will be executed

How can I build a constructor-like function?

When I read the CHAPTER 6 OBJECT-ORIENTED PROGRAMMING of Professional JavaScript for Web Developers, It shows a pattern for create object by constructor.
// implicit way
function Person(name) {
this.name = name;
}
var person1 = new Person('Greg')
person1 instanceof Person
To create a new instance of Person, use the new operator. Calling a constructor in this manner essentially causes the following four steps to be taken:
Create a new object.
Assign the this value of the constructor to the new object (so this points to the new object).
Execute the code inside the constructor (adds properties to the new object).
Return the new object.
That show the implicit way how an object instance be created.
And I want to follow it explicitly. Something like:
function Person(name) {
var o = Object.call(this) // step 1 and step 2
o.name = name // step 3
return o // step 4
}
var person1 = new Person('Greg')
person1 instanceof Person // false
In fact, It can't work as the constructor pattern. Why? And how can I modify my code to create a constructor with the explicit way?
https://javascript.info/constructor-new
Because Object.call(this) makes little sense, as that function does not care of its context and returns a plain object. Instead you can use:
Object.create(this.constructor.prototype)
The book quoted leaves out a seriously important detail of what new does:
1 Create a new object.
really means
1.1 Create a new object,
1.2 which has been prototyped on the constructor function's prototype property.
Hence the results of:
function Person(name) {
var o = Object.create( Person.prototype);
o.name = name // step 3
return o // step 4
}
var person1 = new Person('Greg')
console.log( person1 instanceof Person); // true
console.log( person1.constructor) // Person
Not that you would do this in real code, but for learning purposes it's an interesting demonstration.
The constructor property
Generally an object inherits its "constructor" property from its inheritance chain, searching backwards from the object's __proto property.
You could create a local own-property of an object called "constructor" which would then shadow the inherited value (and which would also be enumerable by default).
If you set the constructor property of a function's prototype property, its value changes without the property becoming enumerable in the process:
function F() {}
console.log (F.prototype.hasOwnProperty("constructor")); // true
let f = new F();
console.log( f.constructor.name); // F
F.prototype.constructor = Object;
let g = new F();
console.log( g.constructor.name); // Object
F.prototype.foo = "bar";
for( var prop in F.prototype) {
console.log( "F.prototype.%s = %s", prop, F.prototype[ prop]); // foo only
}

Javascript Prototype object and Inheritance [duplicate]

I recently stumbled upon the Object.create() method in JavaScript, and am trying to deduce how it is different from creating a new instance of an object with new SomeFunction(), and when you would want to use one over the other.
Consider the following example:
var test = {
val: 1,
func: function() {
return this.val;
}
};
var testA = Object.create(test);
testA.val = 2;
console.log(test.func()); // 1
console.log(testA.func()); // 2
console.log('other test');
var otherTest = function() {
this.val = 1;
this.func = function() {
return this.val;
};
};
var otherTestA = new otherTest();
var otherTestB = new otherTest();
otherTestB.val = 2;
console.log(otherTestA.val); // 1
console.log(otherTestB.val); // 2
console.log(otherTestA.func()); // 1
console.log(otherTestB.func()); // 2
Notice that the same behaviour is observed in both cases. It seems to me that the primary differences between these two scenarios are:
The object used in Object.create() actually forms the prototype of the new object, whereas in the new Function() from the declared properties/functions do not form the prototype.
You cannot create closures with the Object.create() syntax as you would with the functional syntax. This is logical given the lexical (vs block) type scope of JavaScript.
Are the above statements correct? And am I missing something? When would you use one over the other?
EDIT: link to jsfiddle version of above code sample: http://jsfiddle.net/rZfYL/
Very simply said, new X is Object.create(X.prototype) with additionally running the constructor function. (And giving the constructor the chance to return the actual object that should be the result of the expression instead of this.)
That’s it. :)
The rest of the answers are just confusing, because apparently nobody else reads the definition of new either. ;)
The object used in Object.create actually forms the prototype of the new object, where as in the new Function() form the declared properties/functions do not form the prototype.
Yes, Object.create builds an object that inherits directly from the one passed as its first argument.
With constructor functions, the newly created object inherits from the constructor's prototype, e.g.:
var o = new SomeConstructor();
In the above example, o inherits directly from SomeConstructor.prototype.
There's a difference here, with Object.create you can create an object that doesn't inherit from anything, Object.create(null);, on the other hand, if you set SomeConstructor.prototype = null; the newly created object will inherit from Object.prototype.
You cannot create closures with the Object.create syntax as you would with the functional syntax. This is logical given the lexical (vs block) type scope of JavaScript.
Well, you can create closures, e.g. using property descriptors argument:
var o = Object.create({inherited: 1}, {
foo: {
get: (function () { // a closure
var closured = 'foo';
return function () {
return closured+'bar';
};
})()
}
});
o.foo; // "foobar"
Note that I'm talking about the ECMAScript 5th Edition Object.create method, not the Crockford's shim.
The method is starting to be natively implemented on latest browsers, check this compatibility table.
Here are the steps that happen internally for both calls:
(Hint: the only difference is in step 3)
new Test():
create new Object() obj
set obj.__proto__ to Test.prototype
return Test.call(obj) || obj;
// normally obj is returned but constructors in JS can return a value
Object.create( Test.prototype )
create new Object() obj
set obj.__proto__ to Test.prototype
return obj;
So basically Object.create doesn't execute the constructor.
Let me try to explain (more on Blog) :
When you write Car constructor var Car = function(){}, this is how things are internally:
We have one {prototype} hidden link to Function.prototype which is not accessible and one prototype link to Car.prototype which is accessible and has an actual constructor of Car. Both Function.prototype and Car.prototype have hidden links to Object.prototype.
When we want to create two equivalent objects by using the new operator and create method then we have to do it like this: Honda = new Car(); and Maruti = Object.create(Car.prototype).
What is happening?
Honda = new Car(); — When you create an object like this then hidden {prototype} property is pointed to Car.prototype. So here, the {prototype} of the Honda object will always be Car.prototype — we don't have any option to change the {prototype} property of the object. What if I want to change the prototype of our newly created object?
Maruti = Object.create(Car.prototype) — When you create an object like this you have an extra option to choose your object's {prototype} property. If you want Car.prototype as the {prototype} then pass it as a parameter in the function. If you don't want any {prototype} for your object then you can pass null like this: Maruti = Object.create(null).
Conclusion — By using the method Object.create you have the freedom to choose your object {prototype} property. In new Car();, you don't have that freedom.
Preferred way in OO JavaScript :
Suppose we have two objects a and b.
var a = new Object();
var b = new Object();
Now, suppose a has some methods which b also wants to access. For that, we require object inheritance (a should be the prototype of b only if we want access to those methods). If we check the prototypes of a and b then we will find out that they share the prototype Object.prototype.
Object.prototype.isPrototypeOf(b); //true
a.isPrototypeOf(b); //false (the problem comes into the picture here).
Problem — we want object a as the prototype of b, but here we created object b with the prototype Object.prototype.
Solution — ECMAScript 5 introduced Object.create(), to achieve such inheritance easily. If we create object b like this:
var b = Object.create(a);
then,
a.isPrototypeOf(b);// true (problem solved, you included object a in the prototype chain of object b.)
So, if you are doing object oriented scripting then Object.create() is very useful for inheritance.
This:
var foo = new Foo();
and
var foo = Object.create(Foo.prototype);
are quite similar. One important difference is that new Foo actually runs constructor code, whereas Object.create will not execute code such as
function Foo() {
alert("This constructor does not run with Object.create");
}
Note that if you use the two-parameter version of Object.create() then you can do much more powerful things.
The difference is the so-called "pseudoclassical vs. prototypal inheritance". The suggestion is to use only one type in your code, not mixing the two.
In pseudoclassical inheritance (with "new" operator), imagine that you first define a pseudo-class, and then create objects from that class. For example, define a pseudo-class "Person", and then create "Alice" and "Bob" from "Person".
In prototypal inheritance (using Object.create), you directly create a specific person "Alice", and then create another person "Bob" using "Alice" as a prototype. There is no "class" here; all are objects.
Internally, JavaScript uses "prototypal inheritance"; the "pseudoclassical" way is just some sugar.
See this link for a comparison of the two ways.
function Test(){
this.prop1 = 'prop1';
this.prop2 = 'prop2';
this.func1 = function(){
return this.prop1 + this.prop2;
}
};
Test.prototype.protoProp1 = 'protoProp1';
Test.prototype.protoProp2 = 'protoProp2';
var newKeywordTest = new Test();
var objectCreateTest = Object.create(Test.prototype);
/* Object.create */
console.log(objectCreateTest.prop1); // undefined
console.log(objectCreateTest.protoProp1); // protoProp1
console.log(objectCreateTest.__proto__.protoProp1); // protoProp1
/* new */
console.log(newKeywordTest.prop1); // prop1
console.log(newKeywordTest.__proto__.protoProp1); // protoProp1
Summary:
1) with new keyword there are two things to note;
a) function is used as a constructor
b) function.prototype object is passed to the __proto__ property ... or where __proto__ is not supported, it is the second place where the new object looks to find properties
2) with Object.create(obj.prototype) you are constructing an object (obj.prototype) and passing it to the intended object ..with the difference that now new object's __proto__ is also pointing to obj.prototype (please ref ans by xj9 for that)
Object creation variants.
Variant 1 : 'new Object()' -> Object constructor without arguments.
var p1 = new Object(); // 'new Object()' create and return empty object -> {}
var p2 = new Object(); // 'new Object()' create and return empty object -> {}
console.log(p1); // empty object -> {}
console.log(p2); // empty object -> {}
// p1 and p2 are pointers to different objects
console.log(p1 === p2); // false
console.log(p1.prototype); // undefined
// empty object which is in fact Object.prototype
console.log(p1.__proto__); // {}
// empty object to which p1.__proto__ points
console.log(Object.prototype); // {}
console.log(p1.__proto__ === Object.prototype); // true
// null, which is in fact Object.prototype.__proto__
console.log(p1.__proto__.__proto__); // null
console.log(Object.prototype.__proto__); // null
Variant 2 : 'new Object(person)' -> Object constructor with argument.
const person = {
name: 'no name',
lastName: 'no lastName',
age: -1
}
// 'new Object(person)' return 'person', which is pointer to the object ->
// -> { name: 'no name', lastName: 'no lastName', age: -1 }
var p1 = new Object(person);
// 'new Object(person)' return 'person', which is pointer to the object ->
// -> { name: 'no name', lastName: 'no lastName', age: -1 }
var p2 = new Object(person);
// person, p1 and p2 are pointers to the same object
console.log(p1 === p2); // true
console.log(p1 === person); // true
console.log(p2 === person); // true
p1.name = 'John'; // change 'name' by 'p1'
p2.lastName = 'Doe'; // change 'lastName' by 'p2'
person.age = 25; // change 'age' by 'person'
// when print 'p1', 'p2' and 'person', it's the same result,
// because the object they points is the same
console.log(p1); // { name: 'John', lastName: 'Doe', age: 25 }
console.log(p2); // { name: 'John', lastName: 'Doe', age: 25 }
console.log(person); // { name: 'John', lastName: 'Doe', age: 25 }
Variant 3.1 : 'Object.create(person)'. Use Object.create with simple object 'person'. 'Object.create(person)' will create(and return) new empty object and add property '__proto__' to the same new empty object. This property '__proto__' will point to the object 'person'.
const person = {
name: 'no name',
lastName: 'no lastName',
age: -1,
getInfo: function getName() {
return `${this.name} ${this.lastName}, ${this.age}!`;
}
}
var p1 = Object.create(person);
var p2 = Object.create(person);
// 'p1.__proto__' and 'p2.__proto__' points to
// the same object -> 'person'
// { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] }
console.log(p1.__proto__);
console.log(p2.__proto__);
console.log(p1.__proto__ === p2.__proto__); // true
console.log(person.__proto__); // {}(which is the Object.prototype)
// 'person', 'p1' and 'p2' are different
console.log(p1 === person); // false
console.log(p1 === p2); // false
console.log(p2 === person); // false
// { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] }
console.log(person);
console.log(p1); // empty object - {}
console.log(p2); // empty object - {}
// add properties to object 'p1'
// (properties with the same names like in object 'person')
p1.name = 'John';
p1.lastName = 'Doe';
p1.age = 25;
// add properties to object 'p2'
// (properties with the same names like in object 'person')
p2.name = 'Tom';
p2.lastName = 'Harrison';
p2.age = 38;
// { name: 'no name', lastName: 'no lastName', age: -1, getInfo: [Function: getName] }
console.log(person);
// { name: 'John', lastName: 'Doe', age: 25 }
console.log(p1);
// { name: 'Tom', lastName: 'Harrison', age: 38 }
console.log(p2);
// use by '__proto__'(link from 'p1' to 'person'),
// person's function 'getInfo'
console.log(p1.getInfo()); // John Doe, 25!
// use by '__proto__'(link from 'p2' to 'person'),
// person's function 'getInfo'
console.log(p2.getInfo()); // Tom Harrison, 38!
Variant 3.2 : 'Object.create(Object.prototype)'. Use Object.create with built-in object -> 'Object.prototype'. 'Object.create(Object.prototype)' will create(and return) new empty object and add property '__proto__' to the same new empty object. This property '__proto__' will point to the object 'Object.prototype'.
// 'Object.create(Object.prototype)' :
// 1. create and return empty object -> {}.
// 2. add to 'p1' property '__proto__', which is link to 'Object.prototype'
var p1 = Object.create(Object.prototype);
// 'Object.create(Object.prototype)' :
// 1. create and return empty object -> {}.
// 2. add to 'p2' property '__proto__', which is link to 'Object.prototype'
var p2 = Object.create(Object.prototype);
console.log(p1); // {}
console.log(p2); // {}
console.log(p1 === p2); // false
console.log(p1.prototype); // undefined
console.log(p2.prototype); // undefined
console.log(p1.__proto__ === Object.prototype); // true
console.log(p2.__proto__ === Object.prototype); // true
Variant 4 : 'new SomeFunction()'
// 'this' in constructor-function 'Person'
// represents a new instace,
// that will be created by 'new Person(...)'
// and returned implicitly
function Person(name, lastName, age) {
this.name = name;
this.lastName = lastName;
this.age = age;
//-----------------------------------------------------------------
// !--- only for demonstration ---
// if add function 'getInfo' into
// constructor-function 'Person',
// then all instances will have a copy of the function 'getInfo'!
//
// this.getInfo: function getInfo() {
// return this.name + " " + this.lastName + ", " + this.age + "!";
// }
//-----------------------------------------------------------------
}
// 'Person.prototype' is an empty object
// (before add function 'getInfo')
console.log(Person.prototype); // Person {}
// With 'getInfo' added to 'Person.prototype',
// instances by their properties '__proto__',
// will have access to the function 'getInfo'.
// With this approach, instances not need
// a copy of the function 'getInfo' for every instance.
Person.prototype.getInfo = function getInfo() {
return this.name + " " + this.lastName + ", " + this.age + "!";
}
// after function 'getInfo' is added to 'Person.prototype'
console.log(Person.prototype); // Person { getInfo: [Function: getInfo] }
// create instance 'p1'
var p1 = new Person('John', 'Doe', 25);
// create instance 'p2'
var p2 = new Person('Tom', 'Harrison', 38);
// Person { name: 'John', lastName: 'Doe', age: 25 }
console.log(p1);
// Person { name: 'Tom', lastName: 'Harrison', age: 38 }
console.log(p2);
// 'p1.__proto__' points to 'Person.prototype'
console.log(p1.__proto__); // Person { getInfo: [Function: getInfo] }
// 'p2.__proto__' points to 'Person.prototype'
console.log(p2.__proto__); // Person { getInfo: [Function: getInfo] }
console.log(p1.__proto__ === p2.__proto__); // true
// 'p1' and 'p2' points to different objects(instaces of 'Person')
console.log(p1 === p2); // false
// 'p1' by its property '__proto__' reaches 'Person.prototype.getInfo'
// and use 'getInfo' with 'p1'-instance's data
console.log(p1.getInfo()); // John Doe, 25!
// 'p2' by its property '__proto__' reaches 'Person.prototype.getInfo'
// and use 'getInfo' with 'p2'-instance's data
console.log(p2.getInfo()); // Tom Harrison, 38!
Accordingly to this answer and to this video new keyword does next things:
Creates new object.
Links new object to constructor function (prototype).
Makes this variable point to the new object.
Executes constructor function using the new object and implicit perform return this;
Assigns constructor function name to new object's property constructor.
Object.create performs only 1st and 2nd steps!!!
Internally Object.create does this:
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
The syntax just takes away the illusion that JavaScript uses Classical Inheritance.
Object.create(Constructor.prototype) is the part of new Constructor
this is new Constructor implementation
// 1. define constructor function
function myConstructor(name, age) {
this.name = name;
this.age = age;
}
myConstructor.prototype.greet = function(){
console.log(this.name, this.age)
};
// 2. new operator implementation
let newOperatorWithConstructor = function(name, age) {
const newInstance = new Object(); // empty object
Object.setPrototypeOf(newInstance, myConstructor.prototype); // set prototype
const bindedConstructor = myConstructor.bind(newInstance); // this binding
bindedConstructor(name, age); // execute binded constructor function
return newInstance; // return instance
};
// 3. produce new instance
const instance = new myConstructor("jun", 28);
const instance2 = newOperatorWithConstructor("jun", 28);
console.log(instance);
console.log(instance2);
new Constructor implementation contains Object.create method
newOperatorWithConstructor = function(name, age) {
const newInstance = Object.create(myConstructor.prototype); // empty object, prototype chaining
const bindedConstructor = myConstructor.bind(newInstance); // this binding
bindedConstructor(name, age); // execute binded constructor function
return newInstance; // return instance
};
console.log(newOperatorWithConstructor("jun", 28));

Categories