Reputation: 1536
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
?
Upvotes: 2
Views: 71
Reputation: 74204
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.
Upvotes: 1
Reputation: 370689
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);
Upvotes: 4