寒潮ing,你可能在FaceTest中遇到(4)—— 常见的继承方式以及缺点

223 阅读2分钟

创建一个基础的父类构造函数

function God(name='god',age='88') {
    this.name = name;
    this.age = age;
    this.sayName = function() {
        console.log(this.name);
    }
}
God.prototype.sayAge = function() {
    console.log(this.age);
}

我们可以通过下面的几种继承方式获得父类的


1.原型链继承

function Son(name='son') {
    this.name = name;
}
Son.prototype = new God();
let mySon = new Son();
console.log(mySon.name);//son
console.log(mySon.age);//88
mySon.sayName();// son
mySon.sayAge();// 88
console.log(mySon instanceof Son);// true
console.log(mySon instanceof God);// true

实现比较简单,但是 原型对象的所有属性被所有实例共享
借用原型链继承上面代码

let mySon1 = new Son();
let mySon2 = new Son();
mySon1.age = '18';
console.log(mySon2.age);//18

2.构造继承

function Son(name='son') {
    God.call(this);
    this.name = name;
}

let mySon = new Son();
console.log(mySon.name);//son
console.log(mySon.age);//88
mySon.sayName();// son
mySon.sayAge();// undefined
console.log(mySon instanceof Son);// true
console.log(mySon instanceof God);// false
let mySon1 = new Son();
let mySon2 = new Son();
mySon1.age = '18';
console.log(mySon2.age);//88

构造继承避免了共享属性的问题,但是不能继承父类原型上的属性或者方法,实例化对象是子类(Son)


3.组合继承

function Son(name='son') {
    God.call(this);
    this.name = name;
}
Son.prototype = new God();
// 注意这里要改变constructor 指向
Son.prototype.constructor = Son;

let mySon = new Son();
console.log(mySon.name);// son
console.log(mySon.age);// 88
mySon.sayName();// son
mySon.sayAge();// 88
console.log(mySon instanceof Son);// true
console.log(mySon instanceof God);// true

综合了原型链继承和组合继承的优点,除了调用两次父类外几乎无缺点


4.实例继承

function Son(name='son') {
    let instance = new God();
    instance.name = name;
    return instance
}

let mySon = new Son();
console.log(mySon.name);// son
console.log(mySon.age);// 88
mySon.sayName();// son
mySon.sayAge();// 88
console.log(mySon instanceof Son);// false
console.log(mySon instanceof God);// true

继承的是父类God,而不是子类Son


5.拷贝继承

function Son(name='son') {
    let obj = new God();
    for (let key in obj) {
        Son.prototype[key] = obj[key]
    }
    Son.prototype.name = name;
}

let mySon = new Son();
console.log(mySon.name);// son
console.log(mySon.age);// 88
mySon.sayName();// son
mySon.sayAge();// 88
console.log(mySon instanceof Son);// true
console.log(mySon instanceof God);// false

缺点比较明显,需要多次循环,而且无法遍历不可枚举属性


6.寄生组合继承

function Son(name='son') {
    God.call(this);
    this.name = name;
}
// 立即执行函数
(function() {
    // 创建一个中间函数
   let Mid = function() {}
   Mid.prototype = God.prototype;
   Son.prototype = new Mid();
})()
// 注意这里要改变constructor 指向
Son.prototype.constructor = Son;

let mySon = new Son();
console.log(mySon.name);// son
console.log(mySon.age);// 88
mySon.sayName();// son
mySon.sayAge();// 88
console.log(mySon instanceof Son);// true
console.log(mySon instanceof God);// true

缺点是实现复杂,几乎完美的继承



7.9012年了 ES6的class继承该用起来了

class God {
    constructor(name='god',age='88') {
        this.name = name;
        this.age = age;
    }
}
class Son extends God {
    constructor(name='son',sex='M') {
        super(name);
        this.sex = sex;
    }
}

let mySon = new Son();
console.log(mySon.name);// son
console.log(mySon.age);// 88
console.log(mySon.sex);// M
console.log(mySon instanceof Son);// true
console.log(mySon instanceof God);// true