创建 javascript 原型继承链的不同方式

Different ways of creating javascript prototype inheritance chain

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

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

var p = new Parent("Parent");
console.log(p);

function Child(parentName, childName){
  Parent.call(this, parentName);
  this.name = childName; 
}

1. Child.prototype = Object.create(Parent.prototype);
2. Child.prototype = Parent.prototype;

var c = new Child("Parent","Child");
console.log(c);

有人能告诉我上述语句 1 和 2 之间的区别吗。无论哪种方式,子对象都可以调用 c.printName();

两者区别很大, 原型最令人困惑的部分之一是你有原型和 proto.

Protoype是一个特殊的属性函数object,每当你用new关键字调用构造函数时,实例proto,将成为构造函数原型。

Object.create 是允许您创建新 object 的方法,并将其指定为 proto.

因此,当通过方法 1 分配 Child class 原型时,您将给 child class 一个全新的原型 object,即通过protolink,parent的方法通过原型继承来继承。 这是更好的选择,因为您可以在不影响 parent 原型的情况下对 child 原型进行修改,因为它是一个不同的 object.

另一方面,选项 2 您正在为两个 class 分配相同的原型,它们都 引用相同的 object, 因此对 child 原型的更改将影响 parent 原型,这通常不是理想的情况,也不是一个好的做法。

方法一的例子:

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

function Parent(){
  this.x = 0;
}

Parent.prototype.add = function(n){
  this.x+= n;
  return this.x;
};

var parentInstance  = new Parent();
console.log('new Parent instance');
console.log('parentInstance.add(1): ' + parentInstance.add(1));

console.log('now letss add child, which will always add 10, to the add value');

function Child(){
    Parent.call(this);
}
console.log('setting child prototype via method 1');
console.log('Child.prototype = Object.create(Parent.prototype);');
Child.prototype = Object.create(Parent.prototype);
console.log('overriding child add function, to always add 10 to given n');
Child.prototype.add = function(n){
  this.x+= n + 10;
  return this.x;
}
var childInstance  = new Child();
console.log('new child instance');
console.log('childInstance.add(1): ' + childInstance.add(1));
console.log('yay child is working');
console.log('now lets add again to our parent instance');
console.log('parentInstance.add(1): ' + parentInstance.add(1));
console.log('yay parent is still working');

方法 2 的示例:

Child.prototype = Parent.prototype;

function Parent(){
  this.x = 0;
}

Parent.prototype.add = function(n){
  this.x+= n;
  return this.x;
};

var parentInstance  = new Parent();
console.log('new Parent instance');
console.log('parentInstance.add(1): ' + parentInstance.add(1));

console.log('now letss add child, which will always add 10, to the add value');

function Child(){
    Parent.call(this);
}
console.log('setting child prototype via method 2');
console.log('Child.prototype = Parent.prototype;');
Child.prototype = Parent.prototype;
console.log('overriding child add function, to always add 10 to given n');
Child.prototype.add = function(n){
  this.x+= n + 10;
  return this.x;
}
var childInstance  = new Child();
console.log('new child instance');
console.log('childInstance.add(1): ' + childInstance.add(1));
console.log('yay child is working');
console.log('now lets add again to our parent instance');
console.log('parentInstance.add(1): ' + parentInstance.add(1));
console.log('oops we broke parent');

1和2的区别在于

第一个你正在创建一个新的 object 具有指定的原型 object 和属性,不与 parent

共享

Object.create(Parent.prototype) 的作用是 returns 一个 新的 object 与 parent 的原型,但是第二个一个你只是引用(指向)child原型到parent原型,所以如果你添加一个属性到child 原型说,

Child.prototype.age = function(){
  console.log("parent can access this method");
}
p.age();

parent can access this method gets printed, 对于经典继承,您可能希望使用第一种方法,但第二种方法有一些用例

只是对此进行扩展post,我认为最好的继承方式是

// parent object
var Parent = {
    firstname: "john",
    getFirstName  : function () {
        console.log(this.firstname);
    }
};


// create a child object with all the properties and methods of Parent
var child = Object.create(Parent);
// add or modify child properties
child.lastname = "doe";
child.getLastName = function () {
    console.log(this.lastname);
};


// create instances of child object
baby1 = Object.create(child);
baby1.firstname = "alice";
baby1.getFirstName();
baby1.getLastName();

// to see the prototype chain 
console.log("baby1 properties: ", baby1);
console.log("baby1 parent properties: ", baby1.__proto__);
console.log("baby1 grandpa properties: ", baby1.__proto__.__proto__);

非常简单,无需调用或手动原型管理