javaScript几种继承方案的实现

156 阅读3分钟

javaScript几种继承方案的实现

方案一: 原型链继承

让子构造函数的原型指向父构造函数的实例 优点:子实例可以继承父构造函数原型身上的属性和方法

缺点:1. 无法在创建子实例时给父构造函数传递参数

缺点:2. 所有子实例共用父实例的引用类型数据,如本例中son更改了hobbies daughter也受影响

    function Parent() {
        this.name = 'zhangsan',
        this.hobbies = ['跑步','打球']
    }
    Parent.prototype.sayName = function() {
        console.log(this.name);
    }

    function Child(age) {
        this.age = age
    }
    Child.prototype = new Parent()


    // TEST:创建子构造函数实例son、daughter
    let son = new Child(8)
    let daughter = new Child(6)
    son.hobbies.push('打游戏')
    console.log('son :>> ', son);
    console.log('daughter :>> ', daughter);

方案二:借用构造函数继承

在子类构造函数中通过call/apply方法调用父类构造函数

优点:可以在子类构造函数中向父类构造函数传递参数、父类构造函数身上的引用类型属性会分别添加到子类实例身上,改变不会互相影响

缺点:不能继承父类构造函数原型上的属性和方法

    function Parent(name, hobbies) {
        this.name = name,
        this.hobbies = hobbies
    }
    Parent.prototype.sayName = function() {
        console.log(this.name);
    }

    function Child(age, ...args) {
        Parent.apply(this, args)
        this.age = age
    }

    let son = new Child(8, 'zhangsan',['跑步','打球'])
    let daughter = new Child(6, 'zhangsi', ['跑步', '唱歌'])
    son.hobbies.push('打游戏')

    console.log('son :>> ', son);
    console.log('daughter :>> ', daughter);

方案三: 组合继承

结合原型链式继承和借用构造函数继承的优点

优点:既可以在子类构造函数中给父类传参,又能继承父类构造函数原型上的属性和方法

缺点:父类构造函数被调用了两次

    function Parent(name, hobbies) {
        this.name = name,
        this.hobbies = hobbies
    }
    Parent.prototype.sayName = function() {
        console.log(this.name);
    }

    function Child(age, ...args) {
        Parent.apply(this, args)
        this.age = age
    }
    // 原型链继承
    Child.prototype = new Parent()
    Child.prototype.constructor = Child

    let son = new Child(8,'zhangsan',['跑步','打球'])
    let daughter = new Child(6,'zhangsi', ['跑步', '唱歌'])
    son.hobbies.push('打游戏')

    console.log('son :>> ', son);
    console.log('daughter :>> ', daughter);

方案四:原型式继承

以一个已有的对象为原型创建新的实例

优点:可以很方便的继承一个已有对象的属性和方法

缺点:引用类型的属性会被所有新实例共用,互相操作会受影响

    let parent = {
        surname: 'zhang',
        hobbies: ['跑步','打球'],
        sayName: function() {
            console.log(this.surname);
        }
    }

    let son = Object.create(parent)
    let daughter = Object.create(parent)

    son.hobbies.push('打游戏')
    console.log('son :>> ', son.hobbies);
    console.log('daughter :>> ', daughter.hobbies);

方案五:寄生式继承

在原型式继承的基础上拓展新实例的属性和方法

优点:拓展了新实例的属性和方法

缺点:同原型式继承

    function parasInherit(pObj) {
        let newObj = Object.create(pObj)
        newObj.sayHello = function() {
            console.log('Hello');
        }
        return newObj
    }
    let parent = {
        surname: 'zhang',
        hobbies: ['跑步','打球'],
        sayName: function() {
            console.log(this.surname);
        }
    }

    let son = parasInherit(parent)
    son.sayHello()

方案六: 寄生式组合继承

结合了原型式继承和借用构造函数继承、解决了组合继承父构造函数调用两次的缺点

    function Parent(name, hobbies) {
        this.name = name,
        this.hobbies = hobbies
    }
    Parent.prototype.sayName = function() {
        console.log(this.name);
    }

    function Child(age, ...args) {
        Parent.apply(this, args)
        this.age = age
    }
    // 原型式继承
    Child.prototype = Object.create(Parent.prototype)
    Child.prototype.constructor = Child

    let son = new Child(8,'zhangsan',['跑步','打球'])
    let daughter = new Child(6,'zhangsi', ['跑步', '唱歌'])
    son.hobbies.push('打游戏')

    console.log('son :>> ', son);
    console.log('daughter :>> ', daughter);

方案七: Class es6继承

语法简洁,并且可以在初始化子实例时给父类传参

    class Parent {
        constructor(name, hobbies) {
            this.name = name,
            this.hobbies = hobbies
        }
        sayName() {
            console.log(this.name);
        }
    }

    class Child extends Parent {
        constructor(age,name, hobbies) {
            super(name, hobbies)
            this.age = age
        }
    }

    let son = new Child(8, 'zhangsan',['跑步','打球'])
    let daughter = new Child(6,'zhangsi', ['跑步', '唱歌'])
    son.hobbies.push('打游戏')

    console.log('son :>> ', son);
    console.log('daughter :>> ', daughter);