一、 原型链继承
1、 实现方式: 将子类的原型指向父类的对象实例
function Parent() {
this.name = "parent";
this.list = ['a'];
}
Parent.prototype.sayHi = function() {
console.log('hi');
}
function Child() {
}
Child.prototype = new Parent();
var child = new Child();
console.log(child.name);
child.sayHi();
-
原理: 子类实例child的
__proto__
指向Child的原型链prototype,而Child.prototype指向Parent类的对象实例,该父类对象实例的__proto__
指向Parent.prototype,所以Child可继承Parent的构造函数属性、方法和原型链属性、方法 -
优点: 可继承构造函数的属性,父类构造函数的属性,父类原型的属性
-
缺点: 无法向父类构造函数传参,且所有实例共享父类实例的属性,若所有共有属性为引用类型,一个子类实例更该父类构造函数共有属性时会导致继承的共有属性发生变化
var a = new Child(); var b = new Child(); a.list.push('b'); console.log(b.list); // ['a','b']
二、 构造函数继承
1、 实现方式: 在子类构造函数中使用call或者apply劫持父类构造函数方法,并传入参数
2、
function Parent(name, id) {
this.id = id;
this.name = name;
this.printName = function() {
console.log(this.name);
}
}
Parent.prototype.sayName = function() {
console.log(this.name);
}
function Child(name, id) {
Parent.call(this, name, id);
}
var child = new Child("jin","1");
child.printName(); // jin
child.sayName(); // Error
3、 原理: 使用call或apply更改子类函数的作用域,使this执行父类构造函数,子类可以继承父类共有属性
4、
- 优点: 可以向父类构造函数传参
- 缺点: 不可继承父类的原型链方法,构造函数不可复用
三、 组合继承
综合使用构造函数继承和原型链继承
function Parent(name, id) {
this.id = id;
this.name = name;
this.list = ['a'];
this.printName = function() {
concole.log(this.name);
}
}
Parent.prototype.sayName = function() {
console.log(this.name);
}
function Child(name, id) {
Parent.call(this, bane, id);
// Parent.apply(this,arguments);
}
Child.prototype = new Parent();
var child = new Child("jin","1");
child.printName(); // jin
child.sayName(); // jin
var a = new Child();
var b = new Child();
a.list.push("b");
console.log(b.list); // ['a']
2、
- 优点: 可继承父类原型上的属性,且可传参;每个新实例引入的构造函数是私有的
- 缺点: 会执行两次父类的构造函数,消耗较大内存,子类的构造函数会代替原型上的那个父类构造函数
四、 ES6继承
1、 ES6中类class的继承通过extends来实现
- 子类实例可以继承原生构造函数实例的内部属性,ES5不行
-
class A { constructor() { this.a = 'hello' } } class B extends A { constructor() { super(); this.b = 'world' } } let b = new B();
五、 ES6继承与ES5继承的区别
-
- 在ES6中:类B继承了类A的属性
- 在ES5中: 构造函数B没有继承构造函数A的属性
-
继承原生构造函数的情况下
- ES5中,构造函数B的实例继承构造函数A的实例属性是通过A.call(this)实现的
- ES6中,类B的实例继承类A的实例属性,是通过super()实现的