整理面向?qū)ο蟮睦^承

階段一

首先創(chuàng)建一個父類的函數(shù)方便繼承

function Animal(aniamlType,age){
            this.aniamlType = aniamlType
            this.age = age
        }

然后再創(chuàng)建一個子類用來繼承

function Dog(aniamlType, age, name) {
            Animal.call(this, aniamlType, age)
            this.name = name
        }

只需將this傳進去執(zhí)行一遍Animal函數(shù),就能得到所有的屬性了。
但是父類prototype的方法并不會被繼承下來!

function Animal(aniamlType, age) {
        this.aniamlType = aniamlType
        this.age = age
    }
    Animal.prototype.eat = function () {
        console.log('eat')
    }
    function Dog(aniamlType, age, name) {
        Animal.call(this, aniamlType, age)
        this.name = name
    }
    var dog1 = new Dog('dog', '18', 'wb')
    dog1.eat()//Uncaught TypeError: dog1.eat is not a function

階段二

由于父類的方法沒辦法繼承,所以這時候我們就考慮從子類的prototype上來選擇繼承。這樣就能讓實例proto指向子類的prototype的時候能夠得到父類的方法和屬性了。
這時候我們將代碼改一改

        function Animal(aniamlType, age) {
            this.play = ['eat','bite','shout']
        }
        Animal.prototype.eat = function () {
            console.log('eat')
        }
        function Dog(aniamlType, age, name) {
            this.aniamlType = aniamlType
            this.age = age
            this.name = name
        }
        Dog.prototype = new Animal()
        var dog1 = new Dog('dog', '18', 'wb')
        dog1.eat() //eat

可以看到這樣就能讓實例得到父類的方法了。
但是當我再創(chuàng)建一個實例的時候,然后修改父類的時候,由于兩個實例的proto是子類的prototype,而子類的prototype引用同一個地址,即父類的實例(new Animal()),所以修改一個實例里面來自父類的對象的時候,另一個實例的那個對象也會跟著發(fā)生改變

        var dog1 = new Dog('dog', '18', 'wb')
        var dog2 = new Dog('dog', '20', 'wbd')
        dog1.play.push('owwwww')
        console.log(dog1.play)//["eat", "bite", "shout", "owwwww"]
        console.log(dog2.play)//["eat", "bite", "shout", "owwwww"]

這種方法雖然可以繼承父類的方法,但是改變父類對象的時候,其他實例的這個對象也會跟著改變。

階段三

上述兩個階段都有其可取之處,也有缺點。所以我們可以想到,應(yīng)該能兩者一起混合使用。于是就有了第三種方案了。

        function Animal(aniamlType, age) {
            this.aniamlType = aniamlType
            this.age = age
            this.play = ['eat', 'bite', 'shout']
        }
        Animal.prototype.eat = function () {
            console.log('eat')
        }
        function Dog(aniamlType, age, name) {
            Animal.call(this, aniamlType, age, name)//使用階段一來繼承屬性
            this.name = name
        }
        Dog.prototype = new Animal()//使用階段二來繼承方法
        var dog1 = new Dog('dog', '18', 'wb')
        var dog2 = new Dog('dog', '20', 'wbd')
        dog1.play.push('owwwww')
        console.log(dog1.play)//["eat", "bite", "shout", "owwwww"]
        console.log(dog2.play)//["eat", "bite", "shout"]

這時候更改一個實例的時候就不會出現(xiàn)階段三的問題了。
但是子類new,實例也要new一下,會增加性能損耗
于是想到直接等于讓子類的prototype = 父類的prototype好了

        Dog.prototype = Animal.prototype

但是這時候問題又來了,子類在prototype上添加的方法會直接影響到父類的prototype,不方便別的子類繼承該父類。而且子類的constructor會發(fā)生改變。

        Dog.prototype.cat = function () {
            console.log('cat')
        }
        console.log(Animal.prototype.cat) // function () { console('cat') }
        console.log(dog1.constructor)//function Animal ....

在上面會發(fā)現(xiàn)創(chuàng)建實例的竟然是爺爺,而不是爸爸。這就亂套了。
所以這時候就需要將子類的prototype復(fù)制父類的prototype而不是直接引用了。這時候不僅父類沒有了方法,而且還可以直接修改子類的constructor了

        Dog.prototype = Object.create(Animal.prototype)
        Dog.prototype.cat = function () {
            console.log('cat')
        }
        Dog.prototype.constructor = Dog
        console.log(Animal.prototype.cat) //undefined
        console.log(dog1.constructor) //function Dog

這時候才是完美的面向?qū)ο蟮睦^承。
總結(jié):
1.在子類內(nèi)部繼承屬性
2.在子類的prototype上復(fù)制父類的prototype
3.更改子類prototype.constructor,讓其指向自己。


更簡單方便的方法,使用ES6的Class繼承

        class Animal {
            constructor(aniamlType, age) {
                this.aniamlType = aniamlType
                this.age = age
            }
            eat() {
                console.log('eat')
            }
        }
        class Dog extends Animal {
            constructor(aniamlType, age, name) {
                super(aniamlType, age)
                this.name = name
            }
            cat() {
                console.log('cat')
            }
        }
        var dog1 = new Dog('dog', '18', 'wb')
        console.log(dog1.aniamlType, dog1.age, dog1.name)//dog 18 wb
        dog1.cat()//cat
        dog1.eat()//eat
        console.log(dog1.constructor) //class Dog extends Animal {...}

可以看出ES6的class不用那么復(fù)雜了。直接使用,沒有后顧之憂

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容