JS寄生组合式继承中使用Object.create避免共享原型对象

ChatGPT4o 使用 ChatGPT 4o 回答

问题:

JS 寄生组合式继承,为什么要给Child.prototype赋值Object.create(Parent.prototype),直接赋值Parent.prototype不行吗

回答:

在 JavaScript 中,寄生组合式继承是一种常见的继承模式,它结合了原型链继承和借用构造函数继承的优点。具体来说,寄生组合式继承通过以下步骤实现:

  1. 使用 Object.create 创建一个新的对象,这个对象的原型指向父类的原型。
  2. 将这个新对象赋值给子类的原型。
  3. 修正子类原型的 constructor 属性,使其指向子类自身。

下面是一个示例代码:

function Parent(name) {
    this.name = name;
}

Parent.prototype.sayName = function() {
    console.log(this.name);
};

function Child(name, age) {
    Parent.call(this, name); // 借用构造函数继承
    this.age = age;
}

// 寄生组合式继承
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

Child.prototype.sayAge = function() {
    console.log(this.age);
};

const child = new Child('John', 25);
child.sayName(); // John
child.sayAge();  // 25

为什么要使用 Object.create(Parent.prototype) 而不是直接赋值 Parent.prototype

  1. 避免共享原型对象: 如果直接赋值 Child.prototype = Parent.prototype,那么 Child.prototypeParent.prototype 将引用同一个对象。这意味着对 Child.prototype 的任何修改都会影响到 Parent.prototype,反之亦然。这会导致意想不到的副作用和错误。

    Child.prototype = Parent.prototype;
    Child.prototype.sayAge = function() {
        console.log(this.age);
    };
    
    // 现在 Parent.prototype 也有了 sayAge 方法,这是不期望的
    console.log(Parent.prototype.sayAge); // function
    
  2. 正确设置原型链: 使用 Object.create(Parent.prototype) 创建的对象,其原型链会正确地指向 Parent.prototype,但它是一个全新的对象,不会影响到 Parent.prototype。这样可以确保子类和父类的原型链关系正确,同时避免了共享原型对象的问题。

  3. constructor 属性的修正: 直接赋值 Child.prototype = Parent.prototype 会导致 Child.prototype.constructor 指向 Parent,而不是 Child。这会导致一些问题,特别是在需要依赖 constructor 属性的情况下。使用 Object.create 可以避免这个问题,并且可以手动修正 constructor 属性。

    Child.prototype = Object.create(Parent.prototype);
    Child.prototype.constructor = Child;
    

综上所述,使用 Object.create(Parent.prototype) 可以避免共享原型对象的问题,并且可以正确设置原型链和 constructor 属性,从而实现更健壮和灵活的继承机制。