原型继承
function A(){
this.name = [1]
}
function B(){
}
B.prototype = new A()
const test1 = new B()
const test2 = new B()
test1.name.push(2)
console.log(test1.name,test2.name);
输出结果: [1,2],[1,2]
缺点:不是独立的,当继承的属性为对象时,test1会影响到test2
疑问:为什么以下情况不会互相影响
function Super(){
this.name = [1]
}
const test1 = new Super()
const test2 = new Super()
test1.name.push(2)
console.log(test1,test2);
输出结果为:[1,2],[1]
这是因为在new时,Super将里面的this指针变成了实例(test1,test2),相当于一个工厂,每new一次就生成一个独立的对象;而原型继承则是继承的A的实例,当A的实例为一个对象时,因为没有this,那么每次new B时,都会进行引用赋值(浅拷贝)
构造函数继承
可以解决原型继承的引用问题
function Super(){
this.num = [1,2,3]
}
function Sub(){
this.num = [1,2,3]
}
const test1 = new Sub()
const test2 = new Sub()
test1.num.push(4)
console.log(test1.num,test2.num);
将Super的num复制下来就行了,但这么写肯定不行,所以可以
function Super(){
this.num = [1,2,3]
}
function Sub(){
Super.call(this)
}
const test1 = new Sub()
const test2 = new Sub()
test1.num.push(4)
console.log(test1.num,test2.num);
直接执行Super函数,但直接执行会将里面的this指向为window,所以可以用call方法强行改变this指向
构造函数继承完美解决了原型继承带来的问题,但同时也引来了另外一个问题
function Super(){
this.num = [1,2,3]
}
Super.prototype.say = function(){
console.log(222222222);
}
function Sub(){
Super.call(this)
}
const test1 = new Sub()
const test2 = new Sub()
test1.num.push(4)
console.log(test1.num,test2.num);
那就是不能继承Super的say方法
组合继承
组合继承则是将以上两种继承方式进行了整合
function Super(){
this.num = [1,2,3]
}
Super.prototype.say = function(){
console.log(222222222);
}
function Sub(){
Super.call(this)
}
Sub.prototype = new Super() // 将Super中所有的方法都继承了
const test1 = new Sub() // 执行Sub方法,将原型继承的赋值给覆盖掉
const test2 = new Sub()
test1.num.push(4)
console.log(test1.num,test2.num);
test1.say()
test2.say()
通过组合继承解决了以上两种继承方式带来的问题,但组合继承也有其问题所在,那就是Super方法执行了两次
function Super(){
console.log('zyf')
this.num = [1,2,3]
}
Super.prototype.say = function(){
console.log(222222222);
}
function Sub(){
Super.call(this)
}
Sub.prototype = new Super()
const test1 = new Sub()
会输出两次'zyf',原因是以下代码分别调用了一次函数
Sub.prototype = new Super()
和
const test1 = new Sub()
这样的话性能可能不是特别好
寄生组合继承
对组合继承做了优化
function Super(){
console.log('zyf');
this.num = [1,2,3]
}
Super.prototype.say = function(){
console.log(222222222);
}
function Sub(){
Super.call(this)
}
function create(param){
function F(){}
F.prototype = param.prototype
return new F()
}
Sub.prototype = create(Super)
const test1 = new Sub()
这里Super方法只有在new时执行了一次;寄生组合继承就是分别用构造函数继承属性(num)和中间值(F)进行方法继承(say),这样完美解决了以上继承所带来的问题
其中create方法可以用Object.create
Sub.prototype = create(Super)