首页 > 解决方案 > 当通过 Object.setPrototypeOf() 向函数原型添加属性时,对象为空

问题描述

让我们考虑以下代码,

let f = function () {
   this.a = 1;
   this.b = 2;
}

let o = new f(); 
f.prototype.c = 3;
console.log(Object.getPrototypeOf(o)); 

印刷

[对象对象] { c: 3 }

但如果我使用 setPrototypeOf 而不是 f.prototype.c,则该对象为空。

let f = function () {
   this.a = 1;
   this.b = 2;
}

let o = new f();   
Object.setPrototypeOf(f, {c: 3}); 
console.log(Object.getPrototypeOf(o));

印刷

[对象对象] { ... }

但是如果我使用

let f = function () {
   this.a = 1;
   this.b = 2;
}

let o = new f(); 
Object.setPrototypeOf(f, {c: 3}); 
console.log(Object.getPrototypeOf(f)); 

印刷

[对象对象] { c: 3 }

简而言之,问题是,当使用 Object.setPrototypeOf(o) 时,对象打印为空,而当使用 Object.setPrototypeOf(f) 时,对象打印添加的属性。在使用 f.prototype.c = 3 设置原型时,对象原型和函数原型都可以访问它。

标签: javascriptobjectprototype

解决方案


当你Object.setPrototypeOf(f, ... )时,链条实际上是 3 长:

的原型of。的原型f{c:3}

所以你的例子并不等同:

1) 在第一个示例中,您将属性c直接添加到实例f将使用的原型中,因此ocontains的原型cf的构造函数o

在最后两个示例中,您添加c到 的 proto 中f,因此创建了原型f。请记住,函数也只是对象,并且您正在设置用作构造函数的函数的原型。所以 proto 的 proto包含o的 proto 。fc

2) 在第二个例子中,你 getPrototypeOf() o。在第三个中,你 getPrototypeOf() f。因此只有第三个例子c再次显示。

3) 如果您检查 chrome 中的元素,您会看到第二个示例的构造函数是f,因为您询问了 的原型o

在第三个示例中,您将看到构造函数是Object,因为您询问f已设置为对象{c}的 proto 并跳过 proto from oto f

PS:我知道这可能是一个令人困惑的解释。

PPS:如果你想要继承,坚持child.prototype = Object.create( parent.prototype ); child.constructor = child;还是 ES6 类class child extends parent什么时候可以使用它对我个人来说是最少的困惑。

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 );


推荐阅读