从超类继承行为
在上一个挑战中,我们创建了一个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();
|