亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

JavaScript的9種繼承實現方式歸納

2019-11-20 12:27:44
字體:
來源:轉載
供稿:網友

不同于基于類的編程語言,如 C++ 和 Java,JavaScript 中的繼承方式是基于原型的。同時由于 JavaScript 是一門非常靈活的語言,其實現繼承的方式也非常多。

首要的基本概念是關于構造函數和原型鏈的,父對象的構造函數稱為Parent,子對象的構造函數稱為Child,對應的父對象和子對象分別為parent和child。

對象中有一個隱藏屬性[[prototype]](注意不是prototype),在 Chrome 中是__proto__,而在某些環境下則不可訪問,它指向的是這個對象的原型。在訪問任何一個對象的屬性或方法時,首先會搜索本對象的所有屬性,如果找不到的話則會根據[[prototype]]沿著原型鏈逐步搜索其原型對象上的屬性,直到找到為止,否則返回undefined。

1.原型鏈繼承:

原型鏈是 JavaScript 中實現繼承的默認方式,如果要讓子對象繼承父對象的話,最簡單的方式是將子對象構造函數的prototype屬性指向父對象的一個實例:

復制代碼 代碼如下:

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

這個時候,Child的prototype屬性被重寫了,指向了一個新對象,但是這個新對象的constructor屬性卻沒有正確指向Child,JS 引擎并不會自動為我們完成這件工作,這需要我們手動去將Child的原型對象的constructor屬性重新指向Child:
復制代碼 代碼如下:

Child.prototype.constructor = Child

以上就是 JavaScript 中的默認繼承機制,將需要重用的屬性和方法遷移至原型對象中,而將不可重用的部分設置為對象的自身屬性,但這種繼承方式需要新建一個實例作為原型對象,效率上會低一些。

2.原型繼承(非原型鏈):

為了避免上一個方法需要重復創建原型對象實例的問題,可以直接將子對象構造函數的prototype指向父對象構造函數的prototype,這樣,所有Parent.prototype中的屬性和方法也能被重用,同時不需要重復創建原型對象實例:

復制代碼 代碼如下:

Child.prototype = Parent.prototype
Child.prototype.constructor = Child

但是我們知道,在 JavaScript 中,對象是作為引用類型存在的,這種方法實際上是將Child.prototype和Parent.prototype中保存的指針指向了同一個對象,因此,當我們想要在子對象原型中擴展一些屬性以便之后繼續繼承的話,父對象的原型也會被改寫,因為這里的原型對象實例始終只有一個,這也是這種繼承方式的缺點。

3.臨時構造器繼承:

為了解決上面的問題,可以借用一個臨時構造器起到一個中間層的作用,所有子對象原型的操作都是在臨時構造器的實例上完成,不會影響到父對象原型:

復制代碼 代碼如下:

var F = function() {}
F.prototype = Parent.prototype
Child.prototype = new F()
Child.prototype.constructor = Child

同時,為了可以在子對象中訪問父類原型中的屬性,可以在子對象構造器上加入一個指向父對象原型的屬性,如uber,這樣,可以在子對象上直接通過child.constructor.uber訪問到父級原型對象。

我們可以將上面的這些工作封裝成一個函數,以后調用這個函數就可以方便實現這種繼承方式了:

復制代碼 代碼如下:

function extend(Child, Parent) {
    var F = function() {}
    F.prototype = Parent.prototype
    Child.prototype = new F()
    Child.prototype.constructor = Child
    Child.uber = Parent.prototype
}

然后就可以這樣調用:
復制代碼 代碼如下:

extend(Dog, Animal)

4.屬性拷貝:

這種繼承方式基本沒有改變原型鏈的關系,而是直接將父級原型對象中的屬性全部復制到子對象原型中,當然,這里的復制僅僅適用于基本數據類型,對象類型只支持引用傳遞。

復制代碼 代碼如下:

function extend2(Child, Parent) {
    var p = Parent.prototype
    var c = Child.prototype
    for (var i in p) {
        c[i] = p[i]
    }
    c.uber = p
}

這種方式對部分原型屬性進行了重建,構建對象的時候效率會低一些,但是能夠減少原型鏈的查找。不過我個人覺得這種方式的優點并不明顯。

5.對象間繼承:

除了基于構造器間的繼承方法,還可以拋開構造器直接進行對象間的繼承。即直接進行對象屬性的拷貝,其中包括淺拷貝和深拷貝。

淺拷貝:
接受要繼承的對象,同時創建一個新的空對象,將要繼承對象的屬性拷貝至新對象中并返回這個新對象:

復制代碼 代碼如下:

function extendCopy(p) {
    var c = {}
    for (var i in p) {
        c[i] = p[i]
    }
    c.uber = p
    return c
}

拷貝完成之后對于新對象中需要改寫的屬性可以進行手動改寫。

深拷貝:
淺拷貝的問題也顯而易見,它不能拷貝對象類型的屬性而只能傳遞引用,要解決這個問題就要使用深拷貝。深拷貝的重點在于拷貝的遞歸調用,檢測到對象類型的屬性時就創建對應的對象或數組,并逐一復制其中的基本類型值。

復制代碼 代碼如下:

function deepCopy(p, c) {
    c = c || {}
    for (var i in p) {
        if (p.hasOwnProperty(i)) {
            if (typeof p[i] === 'object') {
                c[i] = Array.isArray(p[i]) ? [] : {}
                deepCopy(p[i], c[i])
            } else {
                c[i] = p[i]
            }
        }
    }
    return c
}

其中用到了一個 ES5 的Array.isArray()方法用于判斷參數是否為數組,沒有實現此方法的環境需要自己手動封裝一個 shim。
復制代碼 代碼如下:

Array.isArray = function(p) {
    return p instanceof Array
}

但是使用instanceof操作符無法判斷來自不同框架的數組變量,但這種情況比較少。

6.原型繼承:

借助父級對象,通過構造函數創建一個以父級對象為原型的新對象:

復制代碼 代碼如下:

function object(o) {
    var n
    function F() {}
    F.prototype = o
    n = new F()
    n.uber = o
    return n
}

這里,直接將父對象設置為子對象的原型,ES5 中的 Object.create()方法就是這種實現方式。

7.原型繼承和屬性拷貝混用:

原型繼承方法中以傳入的父對象為原型構建子對象,同時還可以在父對象提供的屬性之外額外傳入需要拷貝屬性的對象:

復制代碼 代碼如下:

function ojbectPlus(o, stuff) {
    var n
    function F() {}
    F.prototype = o
    n = new F()
    n.uber = o

    for (var i in stuff) {
        n[i] = stuff[i]
    }
    return n
}


8.多重繼承:

這種方式不涉及原型鏈的操作,傳入多個需要拷貝屬性的對象,依次進行屬性的全拷貝:

復制代碼 代碼如下:

function multi() {
    var n = {}, stuff, i = 0,
        len = arguments.length
    for (i = 0; i < len; i++) {
        stuff = arguments[i]
        for (var key in stuff) {
            n[i] = stuff[i]
        }
    }
    return n
}

根據對象傳入的順序依次進行拷貝,也就是說,如果后傳入的對象包含和前面對象相同的屬性,后者將會覆蓋前者。

9.構造器借用:

JavaScript中的call()和apply()方法非常好用,其改變方法執行上下文的功能在繼承的實現中也能發揮作用。所謂構造器借用是指在子對象構造器中借用父對象的構造函數對this進行操作:

復制代碼 代碼如下:

function Parent() {}
Parent.prototype.name = 'parent'

function Child() {
    Parent.apply(this, arguments)
}
var child = new Child()
console.log(child.name)


這種方式的最大優勢就是,在子對象的構造器中,是對子對象的自身屬性進行完全的重建,引用類型的變量也會生成一個新值而不是一個引用,所以對子對象的任何操作都不會影響父對象。

而這種方法的缺點在于,在子對象的構建過程中沒有使用過new操作符,因此子對象不會繼承父級原型對象上的任何屬性,在上面的代碼中,child的name屬性將會是undefined。

要解決這個問題,可以再次手動將子對象構造器原型設為父對象的實例:

復制代碼 代碼如下:

Child.prototype = new Parent()

但這樣又會帶來另一個問題,即父對象的構造器會被調用兩次,一次是在父對象構造器借用過程中,另一次是在繼承原型過程中。

要解決這個問題,就要去掉一次父對象構造器的調用,構造器借用不能省略,那么只能去掉后一次調用,實現繼承原型的另一方法就是迭代復制:

復制代碼 代碼如下:

extend2(Child, Parent)

使用之前實現的extend2()方法即可。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产午夜精品全部视频在线播放| 欧美性极品少妇精品网站| 国产va免费精品高清在线| 91亚洲国产成人精品性色| 久久亚洲精品小早川怜子66| 欧美大片在线看免费观看| 久久久国产在线视频| 色av吧综合网| 欧美性xxxxxx| 亚洲二区中文字幕| 欧美孕妇与黑人孕交| 亚洲自拍偷拍区| 26uuu另类亚洲欧美日本一| 92版电视剧仙鹤神针在线观看| 亚洲国产精品推荐| 国产成人免费av| 欧美在线影院在线视频| 成人性生交大片免费观看嘿嘿视频| 欧美激情亚洲精品| 伊人青青综合网站| 精品一区精品二区| **欧美日韩vr在线| 成人黄色免费网站在线观看| 国产香蕉精品视频一区二区三区| 国产精品自拍偷拍视频| 亚洲人午夜精品免费| 精品国产91久久久久久| 久久在线免费观看视频| 国产精品男女猛烈高潮激情| 中文字幕自拍vr一区二区三区| 一夜七次郎国产精品亚洲| 国产精品久久久亚洲| 亚洲国产精品高清久久久| 美女黄色丝袜一区| 日韩中文字幕免费| 久久精品成人欧美大片| 久久影视电视剧免费网站清宫辞电视| 高清一区二区三区日本久| 亚洲精品网址在线观看| 亚洲理论电影网| 亚洲精品视频中文字幕| 欧美性理论片在线观看片免费| 少妇久久久久久| 国产日韩在线精品av| 国产精品人成电影| 久久久99免费视频| 欧美高清性猛交| 成人精品视频99在线观看免费| 色一情一乱一区二区| 亚洲免费视频观看| 中文字幕欧美国内| 欧美激情免费在线| 91日本在线观看| 亚洲精品xxxx| 91久久久在线| 欧美午夜视频一区二区| 欧美日韩中文在线观看| 国产精品爽爽爽爽爽爽在线观看| 91美女片黄在线观看游戏| 国产精品美女999| 日韩欧美亚洲国产一区| 国产欧美一区二区三区久久| 夜夜狂射影院欧美极品| 成人精品福利视频| 久久久亚洲国产| 国产va免费精品高清在线观看| 欧美日韩国内自拍| 久久久亚洲精品视频| 亚洲天堂av在线免费观看| 久久免费视频网| 夜夜嗨av色综合久久久综合网| 欧美性在线视频| 日韩av在线电影网| 国产精品久久97| 国产精品尤物福利片在线观看| 久久视频精品在线| 欧美国产日韩精品| 俺去亚洲欧洲欧美日韩| 久久久久久久久国产| 久久精品国产亚洲精品2020| 欧美国产视频一区二区| 亚洲免费电影一区| 久久久国产精彩视频美女艺术照福利| 亚洲精品ady| 在线日韩精品视频| 国产日韩欧美91| 成人免费视频网址| 国产丝袜一区二区| 国产精品免费久久久久久| 91精品久久久久久综合乱菊| 日韩中文第一页| 国产精品一区二区性色av| 亚洲免费精彩视频| 久久久av网站| 久久久999精品视频| 国产精品专区一| 中文字幕日韩av综合精品| 亚洲乱码国产乱码精品精| 国产精品91在线观看| 国产成人在线一区| 亚洲男人天堂九九视频| 国产精品对白刺激| 亚洲va国产va天堂va久久| 久久精品久久精品亚洲人| 亚洲精品大尺度| 久久中文字幕国产| 日韩国产高清污视频在线观看| 91国产精品视频在线| 亚洲日本成人女熟在线观看| 亚洲图中文字幕| 久久九九国产精品怡红院| 91爱视频在线| 亚洲国产精品高清久久久| 日韩国产在线看| 91精品国产综合久久久久久久久| 国产精品欧美激情在线播放| www.欧美视频| 社区色欧美激情 | 国产精品电影在线观看| 精品亚洲精品福利线在观看| 日韩精品极品在线观看播放免费视频| 亚州欧美日韩中文视频| 成人网欧美在线视频| 欧美性69xxxx肥| 91精品视频免费观看| 国产成人精彩在线视频九色| 久久这里只有精品99| 欧美成人精品h版在线观看| 欧美黑人巨大xxx极品| 久久久精品国产亚洲| 久久全球大尺度高清视频| 91精品国产91久久久| 成人精品福利视频| 欧美在线免费看| 久久精品国产成人精品| 欧美黑人巨大精品一区二区| 欧美专区福利在线| 日韩精品在线私人| 日韩有码视频在线| 日韩免费av一区二区| 国产精品久久久久高潮| 红桃视频成人在线观看| 91久久国产综合久久91精品网站| 日韩在线观看av| 国产v综合ⅴ日韩v欧美大片| 亚洲国产欧美一区二区三区同亚洲| 亚洲欧美日韩一区二区在线| 一区二区三区视频观看| 最近2019中文字幕在线高清| 亚洲国产精品小视频| 色综合伊人色综合网| 日韩美女免费线视频| 国产精品久久久久久久久影视| 成人免费网站在线看| 亚洲欧美国产精品久久久久久久| 亚洲欧洲国产伦综合| 欧美电影在线免费观看网站| 亚洲石原莉奈一区二区在线观看| 91影视免费在线观看| 狠狠色香婷婷久久亚洲精品| 亚洲高清久久网| 欧美大片免费观看在线观看网站推荐| 中文日韩在线视频| 成人中文字幕+乱码+中文字幕|