js继承

70 阅读3分钟

一、原型链继承

  • 优点:所有实例共享一个原型对象
  • 缺点:
    • 1.因为父类已经实例化了,所以在创建子类时无法通过子类传递参数给父类构造函数
    • 2.所有实例共享一个原型对象,当原型中存在引用类型的数据时,一个实例对其修改会影响到所有实例
    function Parent() {
        this.colors = ['red', 'yellow']
    }

    function Son() { }

    Son.prototype = new Parent()
    Son.prototype.constructor = Son

    const son1 = new Son()
    const son2 = new Son()
    son1.colors.push('pink')
    console.log('son2', son2.colors);

二、借用构造函数继承

  • 优点:
    • 1.实例化子类时,可以通过子类传递参数给父类
    • 2.每个实例的成员互不影响,解决引用数据共享的问题
    • 3.构造函数复用,借用构造函数继承允许子类构造函数调用父类构造函数,实现对父类函数的复用
  • 缺点:
    • 1.只能继承父类的属性和方法,无法继承父类的原型
    • 2.无法实现复用,每个子类都有父类实例函数的副本(实例化时都调用父类构造函数,无法复用父类),影响性能
    function Parent() {
        this.age = 12
    }
    function Son() {
        Parent.call(this)
    }

    const son = new Son()
    console.log(son);

三、组合继承

  • 优点:
    • 1.避免了引用数据共享的问题:每个实例都有自己的引用数据副本
    • 2.可以通过子类传递参数给父类
    • 3.调用了两次构造函数,增加性能开销,因为重复调用,导致定义了重复的属性
    function Parent() {
        this.age = 12
    }
    function Son() {
        Parent.call(this)
    }
    Son.prototype = new Parent()
    Son.prototype.constructor = Son

四、原型式继承

利用空对象作为中介,将某个对象直接赋值给空对象构造函数的原型

  • 缺点:
    • 1.原型链继承多个实例的引用数据指向相同,存在篡改的可能
    • 2.无法传递参数
    function createObject(obj) {
        function F() { }
        F.prototype = obj
        return new F();
    }

    const person = {
        name: '1212',
        friends: ['abc', 'def']
    }

    const p1 = createObject(person)
    const p2 = createObject(person)
    p1.friends.push('gg')
    console.log('p2', p2.friends); // ['abc', 'def', 'gg']

五、寄生式继承

在原型式继承的基础上,增强对象,返回构造函数

  • 缺点:与原型式继承一样
    • 1.原型链继承多个实例的引用数据指向相同,存在篡改的可能
    • 2.无法传递参数
    function createAnother(original) {
        // 通过原型链继承对象
        const obj = Object.create(original)
        // 增强对象
        obj.sayHi = function () { }
        return obj
    }

    const person = {
        name: '1212',
        friends: ['abc', 'def']
    }
    const anotherPerson = createAnother(person)

六、寄生组合式继承

结合借用构造函数传递参数和寄生式继承实现继承
寄生组合式继承避免了组合继承中调用两次超类构造函数的问题,同时保留了原型链的完整性,使得子类能够共享父类原型上的方法。这使得寄生组合式继承成为一种相对高效且常用的继承方式。

    function inheritPrototype(child, parent) {
        // 创建一个父类原型的副本
        const prototype = Object.create(parent.prototype);
        // 将副本的构造函数指向子类
        prototype.constructor = child;
        // 将子类原型指向这个副本
        child.prototype = prototype;
    }

    function Parent(name) {
        this.name = name;
        this.colors = ["red", "blue", "green"];
    }

    Parent.prototype.sayHello = function () {
        console.log("Hello, " + this.name);
    };

    function Child(name, age) {
        // 借用构造函数继承属性
        Parent.call(this, name);
        this.age = age;
    }

    // 寄生组合式继承
    inheritPrototype(Child, Parent);

    // 子类可以调用超类的方法,并且原型链保持完整
    const childInstance = new Child("John", 25);
    childInstance.sayHello(); // 输出: Hello, John
    console.log(childInstance.colors); // 输出: ["red", "blue", "green"]

七、class类继承