ES6之前并没有给我们提供 extends 继承。我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承。
一、借用构造函数继承父类型属性
核心原理: 通过 call()
把父类型的 this 指向子类型的 this
,这样就可以实现子类型继承父类型的属性。
例如构建两个函数,一个为父构造函数,一个为子构造函数,如下:
function Father(name,age){
this.name = name;
this.age = age;
}
function Son(name,age){
}
现在想通过子构造函数来继承父构造函数的属性,则在子构造函数内部通过call()
来将子构造函数的this指向指向父构造函数,并打印子构造函数,看其是否继承了父构造函数的属性。
function Father(name,age){
this.name = name;
this.age = age;
}
function Son(name,age){
Father.call(this,name,age);
}
var xl = new Son('小熊',17);
var wh = new Son('王欢',18);
console.log(xl);
打印结果为:
成功继承。
二、借用原型对象继承父类型方法
一般情况下,对象的方法都在构造函数的原型对象中设置,通过构造函数无法继承父类方法。
例如:借助上例的两个构造函数,并给父构造函数通过原型对象添加一个money
方法。
代码如下:
function Father(name,age){
this.name = name;
this.age = age;
}
Father.prototype.money = function(){
console.log('赚了很多钱');
}
function Son(name,age){
Father.call(this,name,age);
}
要实现子构造函数继承父构造函数的方法,如果采用直接赋值的方式,即直接让父原型对象=子原型对象
,可行否呢?
Son.prototype = Father.prototype
var xl = new Son('小熊',17);
console.log(xl);
打印结果为:
发现子构造函数成功继承了父构造函数的方法,但是,如果给子构造函数也添加一个方法,那么,父构造函数的方法会被修改吗?
Son.prototype.study = function(){
console.log('好好学习,天天向上');
}
var xl = new Son('小熊',17);
console.log(xl);
console.log(Father.prototype);
打印结果为:
这时可以发现,子构造函数中的方法在父构造函数中也存在,即修改了子类的原型对象,父类的原型对象也会被修改,所以该方法不可取。
那么应该怎样操作呢?
正确的方法是 :将子类所共享的方法提取出来,让子类的prototype 原型对象
=new 父类()
本质:子类原型对象等于是实例化父类,因为父类实例化之后另外开辟空间,就不会影响原来父类原型对象,将子类的 constructor
从新指向子类的构造函数。
即
Son.prototype = new Father();
创建一个实例对象,可知该原型对象和实例对象是两个不同的内存地址,通过上述代码将Son原型对象指向Father实例对象,又因为Father实例对象可以通过__proto__
属性,访问Father原型对象,所以Son原型就可以间接访问Father原型里面的money
方法。
打印结果为:
即子类继承了父类的方法,反之,子构造函数也添加一个方法,父构造函数的方法会被修改吗?
通过打印的结果,我们发现,子构造函数添加的方法并没有影响到父构造函数的原型。这是因为:Son的原型对象指向的是Father实例对象,Father实例对象和Father原型对象是两个不同的对象,所以不会被影响。