从超类继承行为
在上一个挑战中,我们创建了一个Animal ?超类(supertype ),用来定义所有动物共有的行为:
function Animal() { }
Animal.prototype.eat = function() {
console.log("nom nom nom");
};
在这一节以及下一节挑战中我们将学习如何在?Bird ?和?Dog ?中重用?Animal ?中的方法,而无需重新定义它们。 这里我们会用到构造函数的继承特性。 这一节挑战中我们学习第一步:创建一个超类?supertype (或者叫父类)的实例。 你已经学会了一种创建?Animal ?实例的方法,即使用?new ?操作符:
let animal = new Animal();
此语法用于继承时会存在一些缺点,这些缺点对于当前我们这个挑战来说太复杂了。 相反,我们学习另外一种没有这些缺点的方法来替代 new 操作:
let animal = Object.create(Animal.prototype);
Object.create(obj) ?创建了一个新对象,并指定了?obj ?作为新对象的?prototype 。 回忆一下,我们之前说过?prototype ?就像是创建对象的“配方”。 如果我们把?animal ?的?prototype ?设置为与?Animal ?构造函数的?prototype ?一样,那么就相当于让?animal ?这个实例具有与?Animal ?的其他实例相同的“配方”了。
animal.eat();
animal instanceof Animal;
instanceof ?方法会返回?true .
function Animal() { }
Animal.prototype = {
constructor: Animal,
eat: function() {
console.log("nom nom nom");
}
};
// 只修改这一行下面的代码
let duck = Object.create(Animal.prototype); // 修改这一行
let beagle = Object.create(Animal.prototype); // 修改这一行
将子辈的原型设置为父辈的实例
在上一个挑战中,我们学习了从超类(或者叫父类)?Animal ?继承其行为的第一个步骤:创建一个?Animal ?的新实例。
这一节挑战我们将学习第二个步骤:给子类型(或者子类)设置?prototype 。 这样一来,Bird ?就是?Animal ?的一个实例了。
Bird.prototype = Object.create(Animal.prototype);
请记住,prototype ?类似于创建对象的“配方”。 从某种意义上来说,Bird ?对象的配方包含了?Animal ?的所有关键“成分”。
let duck = new Bird("Donald");
duck.eat();
duck ?继承了Animal ?的所有属性,其中包括了?eat ?方法。
修改你的代码,实现一个继承自?Animal ?的?Dog ?实例。
function Animal() { }
Animal.prototype = {
constructor: Animal,
eat: function() {
console.log("nom nom nom");
}
};
function Dog() { }
// 只修改这一行下面的代码
Dog.prototype = Object.create(Animal.prototype);
let beagle = new Dog("Animal");
重置一个继承的构造函数属性
当一个对象从另一个对象那里继承了其?prototype ?时,那它也继承了父类的 constructor 属性。
请看下面的举例:
function Bird() { }
Bird.prototype = Object.create(Animal.prototype);
let duck = new Bird();
duck.constructor
但是?duck ?和其他所有?Bird ?的实例都应该表明它们是由?Bird ?创建的,而不是由?Animal ?创建的。 为此,你可以手动将?Bird ?的构造函数属性设置为?Bird ?对象:
Bird.prototype.constructor = Bird;
duck.constructor
修改你的代码,使得?duck.constructor ?和?beagle.constructor ?返回各自的构造函数。
function Animal() { }
function Bird() { }
function Dog() { }
Bird.prototype = Object.create(Animal.prototype);
Dog.prototype = Object.create(Animal.prototype);
// 只修改这一行下面的代码
let duck = new Bird();
let beagle = new Dog();
Bird.prototype.constructor = Bird;
Dog.prototype.constructor = Dog;
继承后添加方法
从超类构造函数继承其?prototype ?对象的构造函数,除了继承的方法外,还可以拥有自己的方法。
请看举例:Bird ?是一个构造函数,它继承了?Animal ?的?prototype :
function Animal() { }
Animal.prototype.eat = function() {
console.log("nom nom nom");
};
function Bird() { }
Bird.prototype = Object.create(Animal.prototype);
Bird.prototype.constructor = Bird;
除了从?Animal ?构造函数继承的行为之外,还需要给?Bird ?对象添加它独有的行为。 这里,我们给?Bird ?对象添加一个?fly() ?函数。 函数会以一种与其他构造函数相同的方式添加到?Bird's ?的?prototype ?中:
Bird.prototype.fly = function() {
console.log("I'm flying!");
};
现在?Bird ?的实例中就有了?eat() ?和?fly() ?这两个方法:
let duck = new Bird();
duck.eat();
duck.fly();
duck.eat() ?将在控制台中显示字符串?nom nom nom ,?duck.fly() ?将显示字符串?I'm flying! 。
添加必要的代码,使得?Dog ?对象继承?Animal ,并且把?Dog ?的?prototype 上的 constructor 属性设置为?Dog 。 然后给?Dog ?对象添加一个?bark() ?方法,这样的话,beagle ?将同时拥有?eat() ?和?bark() ?这两个方法。?bark() ?方法中应该输出?Woof! ?到控制台。
function Animal() { }
Animal.prototype.eat = function() { console.log("nom nom nom"); };
function Dog() { }
// 只修改这一行下面的代码
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = () => {
console.log("Woof!")
}
// 只修改这一行上面的代码
let beagle = new Dog();
|