繼承的方法

1.原型鏈繼承

每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象,原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針(constructor),而每個(gè)實(shí)例都包含一個(gè)指向原型對(duì)象的內(nèi)部指針(proto).
實(shí)現(xiàn)原型鏈繼承的基本模式:

        //定義第一個(gè)類型
        function FirstFun() {
            this.num = 1
        }
        //第一個(gè)類型定義方法
        FirstFun.prototype.getFirstNum = function() {
            console.log(this.num);
        }
        //定義第二個(gè)類型
        function SecondFun() {
            this.numb = 2
        }
        //繼承第一個(gè)類型
        SecondFun.prototype = new FirstFun()
        //第二個(gè)類型定義方法
        SecondFun.prototype.getSecondNum = function() {
            console.log(this.numb)
        }
        //第二個(gè)類型添加實(shí)例
        var numbers = new SecondFun()
        //調(diào)用實(shí)例繼承來的方法
        numbers.getFirstNum()
        //結(jié)果打印為:1

原型鏈繼承需注意:
(1)別忘記默認(rèn)原型:
所有函數(shù)的默認(rèn)原型都是object的實(shí)例。因此所有默認(rèn)原型都會(huì)包含一個(gè)內(nèi)部指針,指向object.prototype,這也是所有自定義類型都會(huì)繼承toString()、valueOf()等默認(rèn)方法的根本原因。
(2)確定原型和實(shí)例的方法
第一個(gè):instanceof

alert(numbers instanceof Object)     //true
alert(numbers instanceof FirstFun)   //true
alert(numbers instanceof SecondFun)  //true

第二個(gè):isPrototypeOf()

alert(Object.prototype.isPrototype(numbers))  //true
alert(FirstFun.prototype.isPrototype(numbers))  //true
alert(SecondFun.prototype.isPrototype(numbers))  //true

(3)謹(jǐn)慎定義方法:
給原型添加方法的代碼一定要在替換原型的語(yǔ)句之后。
還有,再通過原型鏈實(shí)現(xiàn)繼承時(shí),不能使用對(duì)象字面量創(chuàng)建原型方法,因?yàn)檫@樣會(huì)重寫原型鏈。

(4)原型鏈存在的問題:

第一個(gè)問題:
引用類型值的原型屬性,會(huì)被所有實(shí)例共享,這正是為什么要在構(gòu)造函數(shù)中,而不是在原型上定義屬性的原因。

        function Obj1() {
            this.colors = ["red","blue","yellow"]
        }

        function Obj2() {
        }

        Obj2.prototype = new Obj1()

        var test1 = new Obj2()
        test1.colors.push("green")
        console.log(test1.colors)  //["red","blue","yellow","green"]

        var test2 = new Obj2
        console.log(test2.colors)  //["red","blue","yellow","green"]

第二個(gè)問題:
沒辦法在不影響所有對(duì)象實(shí)例的情況下,向超類型的構(gòu)造函數(shù)中傳遞參數(shù)。

2.借用構(gòu)造函數(shù)(有時(shí)候也叫偽造對(duì)象或者經(jīng)典繼承)

基本思想:在子類型構(gòu)造函數(shù)內(nèi)部調(diào)用超類型構(gòu)造函數(shù)。

函數(shù)只不過是在特定環(huán)境中執(zhí)行代碼的對(duì)象,因此通過使用apply()或者call()方法也可以在(將來)新創(chuàng)建的對(duì)象上執(zhí)行構(gòu)造函數(shù)。

        function Obj1() {
            this.colors = ["red","blue","yellow"]
        }

        function Obj2() {
            Obj1.apply(this)
        }

        var test1 = new Obj2()
        test1.colors.push("green")
        console.log(test1.colors)  //["red","blue","yellow","green"]

        var test2 = new Obj2
        console.log(test2.colors)  //["red","blue","yellow"]
借用構(gòu)造函數(shù)繼承優(yōu)缺點(diǎn):

(1)優(yōu)點(diǎn):可以在子類型構(gòu)造函數(shù)中向超類型構(gòu)造函數(shù)傳遞參數(shù)。

        function Obj1(name) {
            this.name = name
        }

        function Obj2() {
            //繼承了Obj1,同時(shí)傳遞了參數(shù)
            Obj1.call(this, "Peter")
            this.age = 28
        }

        var test1 = new Obj2()
        console.log(test1.name)  //Peter
        console.log(test1.age)   //28

(2)缺點(diǎn):方法都在構(gòu)造函數(shù)中定義,因此函數(shù)復(fù)用就無從談起。

3.組合繼承(也叫偽經(jīng)典繼承)

思路:
通過使用原型鏈實(shí)現(xiàn)対原型屬性和方法的繼承,通過借用構(gòu)造函數(shù)實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承。

        function Obj1(name) {
            this.name = name
            this.colors = ['aaa','bbb','ccc']
        }

        Obj1.prototype.sayName = function() {
            console.log(this.name);
        }

        function Obj2(name, age) {
            //繼承屬性
            Obj1.call(this, name)
            // 添加新的屬性
            this.age = age
        }

        //繼承方法
        Obj2.prototype = new Obj1()

        //彌補(bǔ)因重寫原型失去的constructor屬性
        Obj2.prototype.constructor = Obj2

        //添加新的方法
        Obj2.prototype.sayAge = function() {
            console.log(this.age);
        }

        var test1 = new Obj2('Peter', 28)
        test1.colors.push('ddd')
        console.log(test1.colors)
        test1.sayName()
        test1.sayAge()

        var test2 = new Obj2('Greo', 33)
        console.log(test2.colors)
        test2.sayName()
        test2.sayAge()
image.png

優(yōu)點(diǎn):組合繼承避免了原型鏈與借用構(gòu)造函數(shù)繼承的缺陷,融合入了他們的優(yōu)點(diǎn)。
缺點(diǎn):無論在什么情況下,都會(huì)調(diào)用兩次超類型構(gòu)造函數(shù)。一次在創(chuàng)建子類型原型的時(shí)候,一次在子類型構(gòu)造函數(shù)內(nèi)部。

4.寄生式繼承

基本思路:創(chuàng)建一個(gè)僅用于封裝繼承過程的函數(shù),該函數(shù)在內(nèi)部以某種方式來增強(qiáng)對(duì)象,最后再像真的是它做了所有工作一樣返回對(duì)象。
寄生式繼承模式:

        function createAnother(original) {
            var clone = Object.create(original)
            clone.sayHi = function() {
                alert("hi")
            }
            return clone
        }

        var person = {
            name:"Daiv",
            friends:["one","two","three"]
        }

        var anotherPerson = createAnother(person)

        anotherPerson.sayHi()

5.寄生組合式繼承

所謂寄生組合式繼承,即通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈的混成形式來繼承方法。
基本思路:
不必為了指定子類型的原型而調(diào)用超類型的構(gòu)造函數(shù),我們需要的無非就是超類型原型的一個(gè)副本而已。本質(zhì)上,就是使用寄生式繼承來繼承超類型的原型,然后再將結(jié)果指定給子類型的原型。
基本模式如下:

//obj1是子類型結(jié)構(gòu),obj2是超類型結(jié)構(gòu)
function inheritPrototype(obj1, obj2){
  //第一步:創(chuàng)建超類型原型副本
  var prototype = object(obj2.prototype)
  //第二步:為創(chuàng)建的副本添加constructor屬性,彌補(bǔ)因?yàn)橹貙懺投サ哪J(rèn)的constructor屬性
  prototype.constructor = obj1
  //第三步:將新創(chuàng)建的對(duì)象(即副本),賦值給子類型的原型
  obj1.prototype = prototype
}

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

SuperType.prototype.sayName = function(){
  alert(this.name)
} 

function SubType(name,age){
  SuperType.call(this,name)
  this.age = age
}

inheritPrototype(SubType,SuperType)

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

相關(guān)閱讀更多精彩內(nèi)容

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