function Human() {
this.name = 'human';
this.sleep = function() {
console.log(this.name + ' sleep');
};
this.friends = [1, 2, 3];
}
Human.prototype.age = 18;
原型链继承
原理:将父类的实例作为子类的原型
function Boy() {
this.name = 'boy';
}
Boy.prototype = new Human();
let b = new Boy();
console.log(b.name); //boy
console.log(b.age); //18
b.sleep(); //boy sleep
console.log(b instanceof Boy); //true
console.log(b instanceof Human); //true
let b2 = new Boy();
b.friends.push(4);
console.log(b.friends, b2.friends); //Array(4) [ 1, 2, 3, 4 ] Array(4) [ 1, 2, 3, 4 ]
- 实例是子类的实例,也是父类的实例
- 来自原型对象的所有引用属性被所有实例共享,在一个实例中修改父类属性,其它实例都会变化
- 创建子类实例时,无法向父类构造函数传参
构造继承
原理:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
function Boy() {
Human.call(this);
this.name = 'boy';
}
let b = new Boy();
console.log(b.age); //undefined
console.log(b instanceof Human); //false
let b2 = new Boy();
b.friends.push(4);
console.log(b.friends, b2.friends); //Array(4) [ 1, 2, 3, 4 ] Array(4) [ 1, 2, 3 ]
- 子类实例不再共享父类属性
- 继承时,可以向父类传递参数
- 可以多继承(call多个父类)
- 不能继承父类原型上的属性和方法
- 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
组合继承
Human.prototype.age = 18;
function Boy() {
Human.call(this);
this.name = 'boy';
}
Boy.prototype = new Human();
let b = new Boy();
console.log(b.name); //boy
console.log(b.age); //18
b.sleep(); //boy sleep
console.log(b instanceof Boy); //true
console.log(b instanceof Human); //true
let b2 = new Boy();
b.friends.push(4);
console.log(b.friends, b2.friends); //Array(4) [ 1, 2, 3, 4 ] Array(4) [ 1, 2, 3 ]
- 弥补了原型链继承和构造继承的缺陷
- 调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
寄生组合继承
function Boy() {
Human.call(this);
this.name = 'boy';
}
Boy.prototype = Object.create(Human.prototype);
Boy.prototype.constructor = Boy;
- 弥补了上述方法的缺陷,堪称完美