参考资料:《JavaScript高级程序设计4》
原型链继承
function Parent() {
this.list = [1,2,3]
}
function Child() {
}
Child.prototype = new Parent()
const child1 = new Child()
const child2 = new Child()
缺点:
- 引用类型的属性被所有实例共享,如下:
...
child1.list.push(4)
console.log(child1)
console.log(child2)
2. 在创建
Child
的实例时,不能向Parent
传参
借用构造函数继承(经典继承)
function Parent(name) {
this.list = [1,2,3]
this.name = name
}
function Child(name) {
Parent.call(this,name)
}
const child1 = new Child('xxx')
const child2 = new Child('ssss')
child1.list.push(4)
优点:
- 避免了引用类型的属性被所有实例共享
- 可以在
Child
中向Parent
传参 缺点: 方法都在构造函数中定义,每次创建实例都会创建一遍方法
组合继承
function Parent(name) {
this.name = name
this.list = [1, 2, 3]
}
Parent.prototype.sayName = function() {
console.log(this.name)
}
function Child(name,age) {
Parent.call(this, name)
this.age = age
}
Child.prototype = new Parent() //此时 Child.prototype 中的 constructor 被重写了,会导致 child1.constructor === Person
Child.prototype.constructor = Child //将 Child 原型对象的 constructor 指针重新指向 Parent 本身
let child1 = new Child('xxx', '18');
child1.list.push(4);
console.log(child1.name);
console.log(child1.age);
console.log(child1.list);
let child2 = new Child('sss', '20');
console.log(child2.name);
console.log(child2.age);
console.log(child2.list);
优点:融合原型链继承和构造函数的优点,是 JavaScript
中最常用的继承模式。
原型式继承
function CreateObj(obj) {
function F(){}
F.prototype = obj
return new F()
}
这种方式也是ES5的Object.create
的模拟实现方式
缺点:
- 与原型链继承一样
引用类型的属性被所有实例共享
const obj = {
name: 'xxx',
list: [1,2,3]
}
const o1 = CreateObj(obj)
const o2 = CreateObj(obj)
o1.list.push(4)
console.log(o1)
console.log(o2)
寄生式继承
创建一个仅用于封装继承过程的函数,该函数在内部以某种形式来做增强对象,最后返回对象。
function createObj (o) {
var clone = Object.create(o);
clone.sayName = function () {
console.log('hi');
}
return clone;
}
缺点:跟借用构造函数模式一样,每次创建对象都会创建一遍方法。
寄生组合式继承
function Parent (name) {
this.name = name;
this.list = [1,2,3];
}
Parent.prototype.getName = function () {
console.log(this.name)
}
function Child (name, age) {
Parent.call(this, name);
this.age = age;
}
// 关键的三步
var F = function () {};
F.prototype = Parent.prototype;
Child.prototype = new F();
var child1 = new Child('xxxx', 18);
console.log(child1);
最后我们封装一下这个继承方法:
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
function prototype(child, parent) {
var prototype = object(parent.prototype);
prototype.constructor = child;
child.prototype = prototype;
}
// 当我们使用的时候:
prototype(Child, Parent);
引用《JavaScript高级程序设计》中对寄生组合式继承的夸赞就是:
这种方式的高效率体现它只调用了一次 Parent 构造函数,并且因此避免了在 Parent.prototype 上面创建不必要的、多余的属性。与此同时,原型链还能保持不变;因此,还能够正常使用 instanceof 和 isPrototypeOf。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。
写在最后
加油搬砖人~~