JS | 构造函数的继承
//定义两个构造函数
function Animal() {
this.species = '动物';
}
function Cat(name.color) {
this.name = name;
this.color = color;
}
&&&
1.使用call和apply方法
这种方法是最简单的方法,使用call和apply方法,.把父对象的构造函数绑定在子对象上
Animal.apply(this,arguments) 或 Animal.call(this,name,color)
function Cat(name,color) {
Animal.apply(this,arguments);
this.name = name;
this.color = color;
}
let cat = new Cat('大毛','黄色');
cat.species; // '动物'
2.原型式继承
这种是最常见的,把一个构造函数的prototype,指向另一个构造函数的实例
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat; //这种方式丢失了原来的constructor属性,所以要手动纠正
let cat = new Cat('二毛','绿色');
cat.species; // '动物'
//每一个实例也有constructor属性,默认调用prototype属性的constructor
cat.constructor = Cat.prototype.constructor; // true
3.直接继承prototype
这种方法是对上一种方法的改进.在Animal对象中,共用的属性都可以写入Animal.prototype,所以我们也可以让Cat() 跳过Animal(),直接继承Animal.prototype
//先改写Animal的prototype属性
function Animal() {}
Animal.prototype.species = '动物';
Cat.prototype = Animal.prototype;
Cat.prototype.constructor = Cat;
let cat = new Cat('三毛','蓝色');
cat.species = '动物';
优点:与上一种方法相比,这样做的效率比较高(不用创建Animal的实例了),比较节省内存.
缺点:因为Cat.prototype和Animal.prototype都指向同一个对象,那么任何对Cat.prototype的修改,都会反应到Animal.prototype
4.利用空对象作为中介
直接继承prototype存在上述缺点,所以就有了第四种写法,利用一个空对象作为中介
function F(){}
F.prototype = Animal.prototype;
Cat.prototype = new F();
Cat.prototype.constructor = Cat;
//这时,修改Cat.prototype对象就不会影响到Animal.prototype
Animal.prototype.constructor; // Animal
把上面这种形式封装成一个方法,便于使用
function extend(Child,Parent) {
let F = function() {};
F.prototype = Parent.prototype;
Child.protype = new F;
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}
这个extend方法,就是YUI库如何实现继承的方法
另外,特别说明一点,函数体最后一行代码 Child.uber = Parent.prototype
意思是为子对象设置一个uber属性,这个属性直接指向父对象的prototype(uber德语的意思是'向上','上一层'),这等于在子对象上打开了一条通道,可以直接调用父对象上的方法.这一行放在这里,只是为了继承的完备性,纯属备用性质
5.拷贝继承
上面是利用了prototype对象实现了继承.我们也可以换一种思路,纯粹采用'拷贝'实现继承.简单说,就是把父对象上的所有属性和方法,都拷贝到子对象身上,这样不也能够实现继承吗
首先还是把Animal身上所有的共用方法,都放到prototype上
function Animal(){}
Animal.prototype.species = '动物';
接下来是继承方法,实现属性拷贝
function extend(Child,Parent) {
let p = Parent.prototype;
let c = Child.prototype;
for(let i in p) {
c[i] = p[i];
}
c.uber = p.prototype;
}
这个对象的目的,就是把Parent.prototype上的属性,逐一拷贝给Child.prototype