js继承

41 阅读2分钟

原型继承

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] image.png 缺点:不是独立的,当继承的属性为对象时,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)