简体   繁体   中英

Object is empty when a property to the prototype of function is added via Object.setPrototypeOf()

Let's consider the following code,

 let f = function () { this.a = 1; this.b = 2; } let o = new f(); f.prototype.c = 3; console.log(Object.getPrototypeOf(o));

Prints

[object Object] { c: 3 }

But if I use setPrototypeOf instead of f.prototype.c, the object is empty.

 let f = function () { this.a = 1; this.b = 2; } let o = new f(); Object.setPrototypeOf(f, {c: 3}); console.log(Object.getPrototypeOf(o));

Prints

[object Object] { ... }

But if I use

 let f = function () { this.a = 1; this.b = 2; } let o = new f(); Object.setPrototypeOf(f, {c: 3}); console.log(Object.getPrototypeOf(f));

Prints

[object Object] { c: 3 }

In short the question is, when using Object.setPrototypeOf(o), the Object prints empty, and when using Object.setPrototypeOf(f), the objects prints the property which is added. where as when setting prototype using f.prototype.c = 3, it is accessible by both Objects prototype and the functions prototype.

When you Object.setPrototypeOf(f, ... ) , the chain is actually 3 long:

The prototype of o is f . The prototype of f is {c:3} .

So your examples are not equivalent to each other:

1) In the first example, you add the property c directly to the prototype that instances of f will use, so the proto of o contains c since f is the constructor for o .

In the last two examples you add c to the proto of f , so the prototype f was created with. Remember that functions are also just objects and that you're setting the proto of a function you use as a constructor. So the proto of o contains the proto of f which contains c .

2) In the 2nd example, you getPrototypeOf() o . In the 3rd, you getPrototypeOf() f . Hence only the 3rd example shows c again.

3) If you inspect the element in chrome, you see that the constructor of the 2nd example is f , since you ask the proto of o .

In the 3rd example you'll see that the constructor is Object , since you ask the proto of f , which has been set to the object {c} and skip the proto from o to f .

PS: I'm aware this is might be a confusing explanation.

PPS: If you want inheritance, sticking to child.prototype = Object.create( parent.prototype ); child.constructor = child; child.prototype = Object.create( parent.prototype ); child.constructor = child; or ES6 class class child extends parent when it can be used led to the least confusion for me personally.

 var first = function first() { this.value = 'first function'; }; // before .prototype.extra, first inherist from Function. console.log( 'constructor of first before:', first.constructor ); first.prototype.extra = 'implemented with .prototype.extra'; // after .prototype.extra, first still inherits from Function, we did not change anything to first itself. console.log( 'constructor of first after:', first.constructor ); // When first is used as a prototype, the instances will get "extra". // Aka, everything that inherist from first. var first_instance = new first(); console.log( 'extra on instance of first:', first_instance.extra ); // f itself does NOT have the extra property, only instances of first do. console.log( 'extra on first itself:', first.extra ); console.log( '------' ); var second = function second() { this.value = 'second function'; }; // before setPrototypeOf, second inherist from Function, like above. console.log( 'constructor of second before:', second.constructor ); Object.setPrototypeOf( second, { extra: 'implemented with .setPrototypeOf()' }); // after setPrototypeOf, second inherist from Object, we broke the default inheritance chain. console.log( 'constructor of second after:', second.constructor ); // BY doing this, we effectively turned second into an object. // It no longer is a function, so we cannot use function methods like .call() or .apply() console.log( 'second is object, not function: function.apply', second.apply ); console.log( 'second is object, not function: object.hasOwnProperty', second.hasOwnProperty ); // When second is used as a prototype, the instances will not get "extra". var second_instance = new second(); console.log( 'extra on instance of second:', second_instance.extra ); // second itself Does have the extra property, sine we assigned it on the prototype used by second. not when second is used as the prototype. console.log( 'extra on second itself:', second.extra );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM