解惑:F.prototype在构造函数内外设置的工作机制差异
为什么构造函数内部设置
prototype无法让实例继承方法? 核心原因
当调用new F()创建实例时,实例的__proto__会在构造函数执行前就绑定到当前的F.prototype。构造函数内部修改F.prototype的操作发生在实例的原型绑定之后,所以已经创建的实例不会同步这个变化。
拆解new操作符的执行流程
以new SlimZ2("Lili")为例,实际执行步骤是:
- 创建空对象
s2 - 将
s2.__proto__赋值为当前的SlimZ2.prototype(此时SlimZ2.prototype是默认的{constructor: ƒ SlimZ2}) - 执行构造函数
SlimZ2,把this绑定到s2上,设置this.name = "Lili",然后修改SlimZ2.prototype为包含jump的新对象 - 返回
s2
这就导致s2.__proto__还是最初的默认原型对象,而SlimZ2.prototype已经被替换成新对象,二者自然不相等,s2也找不到jump方法。
而第一个示例中,我们在调用new SlimZ1("Lili")之前就修改了SlimZ1.prototype,所以步骤2中s1.__proto__直接指向了包含jump的原型对象,实例自然能正常调用方法。
构造函数内设置原型的正确方式
如果非要在构造函数内调整实例的原型,有两种常见方式:
- 直接设置实例的原型(推荐用标准API):
let SlimZ3 = function(name) { this.name = name; // 用标准方法设置实例的原型 Object.setPrototypeOf(this, animal); } - 把方法添加到实例自身(这不是原型继承,每个实例都会复制方法):
let SlimZ4 = function(name) { this.name = name; // 把animal的方法复制到当前实例 Object.assign(this, animal); }
你的示例代码
示例1:构造函数外设置prototype(正常工作)
let animal = { jump: function () { alert(`Hey ${this.name}, Bounce! Bounce! Bounce!`); } } let SlimZ1 = function (name) { this.name = name; }; // 尝试将animal的方法引入SlimZ1 SlimZ1.prototype = { ...animal, constructor: SlimZ1 } // 创建实例后可正常工作 let s1 = new SlimZ1("Lili") s1.jump() // 正常执行 s1.__proto__ === SlimZ1.prototype // true,因为二者均为{jump: ƒ, constructor: ƒ}
示例2:构造函数内设置prototype(无法工作)
let animal = { jump: function () { alert(`Hey ${this.name}, Bounce! Bounce! Bounce!`); } } let SlimZ2 = function SlimZ2(name) { this.name = name; SlimZ2.prototype = { ...animal, constructor: SlimZ2 } }; // 创建实例后无法正常工作 let s2 = new SlimZ2("Lili") s2.jump() // 停止工作 s2.__proto__ === SlimZ2.prototype // false // s2.__proto__ | {constructor: ƒ} // SlimZ2.prototype | {jump: ƒ, constructor: ƒ}
内容的提问来源于stack exchange,提问作者Jonas Kahn
相关产品推荐
相关产品推荐

