一文读懂原型继承

在传统 JavaScript 中,有一种伪装的继承概念,它是通过使用原型技术来实现的。在ES5、ES6中看到使用 new 的语法只是底层原型OOP的语法糖。创建类是使用 JavaScript 中的函数完成的。

var animalGroups = {
  MAMMAL: 1,
  REPTILE: 2,
  AMPHIBIAN: 3,
  INVERTEBRATE: 4
};
function Animal(name, type) {
  this.name = name;
  this.type = type;
}
var dog = new Animal("dog", animalGroups.MAMMAL);
var crocodile = new Animal("crocodile", animalGroups.REPTILE);

这里我们为类创建对象(使用 new 关键字),可以使用如下方式对类追加方法:

Animal.prototype.shout = function() {
  console.log(this.name+'is'+this.sound+'ing...');
}

这里你可能会有疑问。类中并没 sound 属性。是的,它打算由继承了上述类的子类传递。JavaScript中, 如下实现继承:

function Dog(name, type) {
Animal.call(this, name, type);
this.sound = 'bow';
}

我定义了一个更具体的函数,叫做 Dog。在这里,为了继承 Animal 类,我需要call传递this和其他参数。使用如下方式来实例化一只德国牧羊犬

var pet = Dog("德国牧羊犬", animalGroups.MAMMAL);
console.log(pet); // returns Dog {name: "德国牧羊犬", type: 1, sound: "bow"}

我们没有在子函数中分配 name 和 type 属性,我们调用的是超级函数 Animal 并设置相应的属性。pet 具有父类的属性(name、type)。但是方法呢。他们也继承的吗? 来看看:

pet.shout(); // Throws error

为什么会这样? 之所以发生这种情况,是因为没有指定让 JavaScript来继承父类方法。 如何解决?

// Link prototype chains
Dog.prototype = Object.create(Animal.prototype);
var pet = new Dog("germanShepard", animalGroups.MAMMAL);
// Now shout method is available
pet.shout(); // 德国牧羊犬 bowing...

现在可以使用 shout 方法。 我们可以使用 object.constructor 函数检查 JavaScript 中给定对象的类 来看看 pet 是什么类:

pet.constructor; // returns Animal

这是模糊的,Animal 是一个父类。但是 pet 到底是什么类型的呢? pet 应该是 Dog 的类型。之所以是 Animal 类型,是因为 Dog 类的构造函数:

Dog.prototype.constructor; // returns Animal

它是 Animal 类型的。我们应该将它设置为 Dog 本身,这样类的所有实例(对象)才能给出正确的类名。

Dog.prototype.constructor = Dog;

关于原型继承, 我们应该记住以下几条:

  • 类属性使用 this 绑定

  • 类方法使用 prototype 对象来绑定

  • 为了继承属性, 使用 call 函数来传递 this

  • 为了继承方法, 使用 Object.create 连接父和子的原型

  • 始终将子类构造函数设置为自身,以获得其对象的正确类型

猜你喜欢

转载自www.cnblogs.com/art-poet/p/12050555.html