当需要创建新的对象时,继承是一个必须考虑的问题。JavaScript中的继承方式花样繁多,以下是常见的7种继承方式。
1.原型链继承
将父类的实例作为子类的原型,实现继承,示例代码如下:
function Parent() {
this.name = 'parent';
}
Parent.prototype.getName = function() {
return this.name;
};
function Child() {
this.age=20;
}
Child.prototype=new Parent();
Child.prototype.getAge = function() {
return this.age;
};
var child = new Child();
console.log(child.getName()); // parent
console.log(child.getAge()); // 20
缺点:原型链继承存在共享父类属性的缺点,对父类属性的修改会影响到所有子类实例。同时,无法向父类构造函数传参。
2.借用构造函数继承
在子类的构造函数中调用父类的构造函数,通过call和apply方法,在子类实例对象上执行构造函数中的代码,从而实现继承。示例如下:
function Parent(name) {
this.name = name;
this.getName = function() {
return this.name;
};
}
function Child(name, age) {
// 在子类构造函数中使用apply调用父类构造函数,将父类的name变量绑定到实例对象上
Parent.apply(this, [name]);
this.age = age;
this.getAge = function() {
return this.age;
};
}
var child = new Child('lucifer', 20);
console.log(child.getName()); // lucifer
console.log(child.getAge()); // 20
优点:借用构造函数继承解决了共享父类属性的问题,同时可以向父类构造函数传递参数。
缺点:每个子类对象都只能访问它自己的属性和方法,不能共享父类的原型中定义的属性和方法。
3.组合继承
将原型链继承和借用构造函数继承组合起来。即通过借用构造函数来继承父类的属性和方法,在子类原型中定义方法实现对父类原型的继承,即同时继承属性和方法。不过,这样做也会存在一些缺点,比如调用了两次父类构造函数。示例代码如下:
function Parent(name) {
this.name = name;
this.colors = ['red', 'green', 'blue'];
}
Parent.prototype.getName = function() {
return this.name;
};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
Child.prototype.getAge = function() {
return this.age;
};
var child1 = new Child('lucifer', 20);
child1.colors.push('white');
console.log(child1.getName()); // lucifer
console.log(child1.getAge()); // 20
console.log(child1.colors); // [ 'red', 'green', 'blue', 'white' ]
var child2 = new Child('zhenyuan', 18);
console.log(child2.getName()); // zhenyuan
console.log(child2.getAge()); // 18
console.log(child2.colors); // [ 'red', 'green', 'blue' ]
优点:既继承了父类原型上的方法,又继承了父类构造函数上的属性,属性不会再对象之间共享,可以传参。
缺点:其缺点是调用了两次父类构造函数,生成了两份实例。
4.原型式继承
通过指定一个对象作为新对象的原型,基于已有的对象创建一个新的对象。比实现继承的第一种方式(原型链继承)更加灵活。示例代码如下:
function createObj(o) {
function F(){}
F.prototype=o;
return new F();
}
var person={
name:'lucifer',
colors:['red','green','blue']
}
var child=createObj(person);
child.colors.push('white');
console.log(child.name) // lucifer
console.log(child.colors) // [ 'red', 'green', 'blue', 'white' ]
缺点:浅拷贝,存在引用类型共享的问题。
5.寄生式继承
与原型式继承类似,但略微不同。基本思路是创建一个仅用于封装继承过程的临时构造函数,最后返回这个构造函数。示例代码如下:
function inheritObj(obj) {
var clone = Object.create(obj);
clone.sayName = function() {
console.log('hi');
};
return clone;
}
var person = {
name: 'lucifer',
colors: ['red', 'green', 'blue']
};
var child = inheritObj(person);
优点:在原型式继承的基础上,添加了新的属性和方法,相对原型式继承更加灵活。
缺点:无法复用父类的方法,与组合继承类似存在两份构造函数和原型。
6.寄生组合式继承
通过借用构造函数来继承属性,通过原型链的混合形式来继承方法。这种继承方式比较经典,是继承的最优解。示例代码如下:
function Parent(name) {
this.name = name;
this.colors = ['red', 'green', 'blue'];
}
Parent.prototype.getName = function() {
return this.name;
};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.getAge = function() {
return this.age;
};
var child1 = new Child('lucifer', 20);
child1.colors.push('white');
console.log(child1.getName()); // lucifer
console.log(child1.getAge()); // 20
console.log(child1.colors); // [ 'red', 'green', 'blue', 'white' ]
var child2 = new Child('zhenyuan', 18);
console.log(child2.getName()); // zhenyuan
console.log(child2.getAge()); // 18
console.log(child2.colors); // [ 'red', 'green', 'blue' ]
优点:不存在调用父类构造函数两次的问题,完美避免了父类构造函数与子类构造函数之间的耦合,也不存在共享父类属性的问题,同时父类原型上的方法可以正常继承。
7.class继承
ES6新增了class关键字,标准化了JavaScript中的继承方式,可以更简洁地实现继承,代码更易读、易写,利于代码的维护。示例代码如下:
class Parent {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
class Child extends Parent {
constructor(name, age) {
super(name);
this.age = age;
}
getAge() {
return this.age;
}
}
const child = new Child('lucifer', 20);
console.log(child.getName()); // lucifer
console.log(child.getAge()); // 20
优点:用class实现继承,简化了代码实现的难度,并且代码更加清晰易理解。
综上,以上七种继承方式各有优劣,具体应根据需求场景选择合适的继承方式。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript中常见的七种继承及实现 - Python技术站