继承 extends
1. 继承实现方式(一):原型链 / 构造函数 / 组合
原型链继承
将子类原型绑定到父类实例上:
function Parent() {
this.name = 'parent1';
this.play = [1, 2, 3];
}
function Child() {
this.type = 'child2';
}
Child.prototype = new Parent();
const s1 = new Child();
const s2 = new Child();
s1.play.push(4);
console.log(s1.play, s2.play); // [1, 2, 3, 4]、[1, 2, 3, 4]
缺点:改变 s1.play,s2.play 也跟着变,因为两个实例共用同一个原型对象,引用类型共享内存。
构造函数继承
借助 call 调用父类构造函数:
function Parent() {
this.name = 'parent1';
}
Parent.prototype.getName = function () { return this.name; };
function Child() {
Parent.call(this);
this.type = 'child';
}
const child = new Child();
console.log(child); // { name: 'parent1', type: 'child' }
console.log(child.getName()); // 报错:getName is not a function
缺点:只能继承父类的实例属性,不能继承原型属性 / 方法。
组合继承
结合上面两种方式:
function Parent3() {
this.name = 'parent3';
this.play = [1, 2, 3];
}
Parent3.prototype.getName = function () { return this.name; };
function Child3() {
Parent3.call(this); // 第二次调用 Parent3
this.type = 'child3';
}
Child3.prototype = new Parent3(); // 第一次调用 Parent3
Child3.prototype.constructor = Child3;
const s3 = new Child3();
const s4 = new Child3();
s3.play.push(4);
console.log(s3.play, s4.play); // [1,2,3,4]、[1,2,3] 不互相影响
console.log(s3.getName()); // 'parent3'
缺点:父类被执行了两次,造成多构造一次的性能开销。
2. 继承实现方式(二):原型式 / 寄生式 / 寄生组合式
原型式继承
借助 Object.create:
const parent4 = {
name: 'parent4',
friends: ['p1', 'p2', 'p3'],
getName() { return this.name; }
};
const person4 = Object.create(parent4);
const person5 = Object.create(parent4);
缺点:Object.create 是浅拷贝,多个实例引用类型属性指向同一块内存。
寄生式继承
const parent5 = {
name: 'parent5',
friends: ['p1', 'p2', 'p3'],
getName() { return this.name; }
};
function clone(original) {
const cloneObj = Object.create(original);
cloneObj.getFriends = function () { return this.friends; };
return cloneObj;
}
const person5 = clone(parent5);
缺点:同原型式继承,浅拷贝。
寄生组合式继承(最优解)
借助 Object.create 改造,是所有继承方式里最优的。
function clone(parent, child) {
child.prototype = Object.create(parent.prototype);
child.prototype.constructor = child;
}
function Parent6() {
this.name = 'parent6';
this.play = [1, 2, 3];
}
Parent6.prototype.getName = function () { return this.name; };
function Child() {
Parent6.call(this);
this.friend = 'child5';
}
clone(Parent6, Child);
const person = new Child();
通过
Object.create来划分不同的继承方式,最后的寄生式组合继承是组合继承改造后的最优继承方式,而 ES6class extends的语法糖和寄生组合继承的方式基本类似。
来源整理自:我的有道云笔记



