1. 借助构造函数实现继承
function Parent1() {
this.name = 'Parent1';
}
Parent1.prototype.say = function() {
console.log('你好');
}
function Child1() {
Parent1.call(this); // !!!关键点 apply也可以
this.type = 'child1';
}
let s1 = new Child1();
console.log(s1);
s1.say(); // 此处会报错
关键是 Parent1.call() 这一句,是通过call(apply)改变函数运行上下文,将Parent1的this挂载到Child1的实例上
缺点1:Parent1原型链上边的属性方法等不会被继承。
2.借助原型链继承
function Parent2() {
this.name = 'parent2';
this.arr = [1,2,3];
}
function Child2() {
this.name = 'child2'
}
Child2.prototype = new Parent2(); // 此处为关键
let s2 = new Child2();
let s3 = new Child2();
console.log(s2.arr, s3.arr) // [1,2,3] [1,2,3]
如上,关键在于将Child2的原型指向Parent2的实例
缺点2:这样构造的Child2的实例,都是同一个原型,改变其中一个,其他的实例也会改变
如,接上边,再增加一句
s2.arr.push(4);
console.log(s2.arr, s3.arr); //[1,2,3,4] [1,2,3,4]
可见,修改s2的arr属性,s3实例也跟着变化
3.组合继承 (解决上边缺点1、2)
// 组合继承
function Parent3() {
this.name = 'parent3';
this.arr = [1,2,3];
}
function Child3() {
Parent3.call(this);
this.name = 'child3'
}
Child3.prototype = new Parent3();
let s4 = new Child3();
let s5 = new Child3();
s4.arr.push(4)
console.log(s4.arr, s5.arr) // [1,2,3,4] [1,2,3]
缺点3: Child3每次实例化,都要执行Parent3 构造函数,
4.组合继承的优化1
function Parent4() {
this.name = 'parent4';
this.arr = [1,2,3];
}
function Child4() {
Parent4.call(this);
this.name = 'child4'
}
Child4.prototype = Parent4.prototype; // !!!此处为关键
let s6 = new Child4();
let s7 = new Child4();
s6.arr.push(4)
console.log(s6.arr, s7.arr)
缺点4: 无法区分实例是由Child4还是Parent4直接实例化而来
console.log(s6 instanceof Child4, s6 instanceof Parent4); // 可以发现此时均为 true
console.log(s6.constructor, s7.constructor); // 均为Parent4
5.组合继承2
function Parent5() {
this.name = 'parent5';
this.arr = [1,2,3];
}
function Child5() {
Parent5.call(this);
this.name = 'child5'
}
Child5.prototype = Object.create(Parent5.prototype); // !! 此处为关键
let s8 = new Child5();
let s9 = new Parent5();
console.log(s8 instanceof Child5, s9 instanceof Child5); // true, false
console.log(s8.constructor, s9.constructor); // 均为Parent5
关键在于,通过 Object.create 构造一个中间对象,用以区分
缺点:两者 constructor 还是全部指向 Parent5
可通过如下手动设置,解决
Child5.prototype.constructor = Child5;