JS继承方式
JS作为面向对象的弱类型语言,继承也是其非常强大的特性之一。
那么如何在JS中实现继承呢?JS实现继承有多重方式,但是没中方式都有优缺点。
常见的继承方法有:
-
原型链继承
-
构造继承
-
实例继承
-
拷贝继承
-
组合继承
-
寄生组合继承
-
ES6-Class-Extends
父类
首先我们先定义一个父类,实现代码如下:
function Animal( name="Animal" ){
// 属性
this.name = name;
// 实例方法
this.showName = ()=>{
console.log( `showName: ${this.name}` );
}
}
// 原型方法
Animal.prototype.outputName = function(){
console.log( `outputName: ${this.name}` );
}
继承方式
原型链继承
将父类的实例作为子类的原型
Cat.prototype = new Animal();
function Cat( name="maomi" ){
this.name = name;
}
Cat.prototype = new Animal();
// 测试代码
let cat = new Cat();
cat.showName(); // showName: maomi
cat.outputName(); // outputName: maomi
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
缺点:
-
无法实现多继承
-
创建子类实例时,无法向父类构造函数传参
构造继承
复制父类的实例属性给子类
Animal.call(this);
function Cat(name){
Animal.call(this);
this.name = name || 'maomi';
}
// 测试代码
var cat = new Cat();
cat.showName(); // showName: maomi
// cat.outputName(); // 报错。无法执行
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
缺点:
- 只继承父类的实例属性/方法,无法继承原型的属性/方法
实例继承
在构造函数实例化父类,然后作为子类实例返回
function Cat( name="maomi" ){
var instance = new Animal();
instance.name = name;
return instance;
}
// 测试代码
var cat = new Cat();
cat.showName(); // showName: maomi
cat.outputName(); // outputName: maomi
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false
缺点:
- 实例是父类的实例,不是子类的实例
拷贝继承
通过对父类实例可枚举对线进行拷贝
function Cat( name="maomi" ){
let animal = new Animal();
for( let _prototype in animal ){
Cat.prototype[_prototype] = animal[_prototype];
}
this.name = name;
}
// 测试代码
var cat = new Cat();
cat.showName(); // showName: maomi
cat.outputName(); // outputName: maomi
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false
缺点:
- 实例是父类的实例,不是子类的实例
组合继承
构造继承+原型链阶层,修复原型链指向
function Cat( name="maomi" ){
Animal.call( this );
this.name = name;
}
Cat.prototype = new Animal();
// 测试代码
var cat = new Cat();
cat.showName(); // showName: maomi
cat.outputName(); // outputName: maomi
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
缺点:
- 调用了两次父类构造函数,生成了两份实例
寄生组合继承
通过构造继承复制父类属性
然后修复原型链
function Cat( name="maomi" ){
Animal.call( this );
this.name = name;
}
(function(){
// 创建一个没有实例方法的类
var Super = function(){};
Super.prototype = Animal.prototype;
//将实例作为子类的原型
Cat.prototype = new Super();
})();
Cat.prototype.constructor = Cat;
// 测试代码
var cat = new Cat();
cat.showName(); // showName: maomi
cat.outputName(); // outputName: maomi
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
ES6继承
class Animal{
constructor( name="Animal" ){
this.name = name;
}
showName(){
console.log( this.name )
}
}
class Cat extends Animal{
constructor( name="Maoni" ){
super( name )
}
}
let cat = new Cat();
cat.showName(); // Maoni
【参考文章】