構(gòu)造函數(shù)繼承-非構(gòu)造函數(shù)繼承

1.constructor

為了解決從原型對(duì)象生成實(shí)例的問題,JavaScript提供了一個(gè)構(gòu)造函數(shù)(Constructor)模式,本質(zhì)還是一個(gè)普通函數(shù),但是內(nèi)部使用了this變量。對(duì)構(gòu)造函數(shù)使用new運(yùn)算符,就能生成實(shí)例,并且this變量會(huì)綁定在實(shí)例對(duì)象上。

這時(shí)cat1會(huì)自動(dòng)含有一個(gè)constructor屬性,指向他們的構(gòu)造函數(shù)。也就是Cat

js還提供了instanceof運(yùn)算符,驗(yàn)證原型對(duì)象和實(shí)例對(duì)象之間的關(guān)系

console.log(cat1 instanceof Cat) // 會(huì)打印出一個(gè)true?

2.constructor的不足

假如為Cat對(duì)象添加一個(gè)不變的屬性和方法,比如type為‘貓科動(dòng)物’,方法為‘eat Mouse’,那就是對(duì)于每一個(gè)實(shí)例對(duì)象,type屬性和eat()方法都是一模一樣的內(nèi)容,每一次生成一個(gè)實(shí)例,都必須為重復(fù)的內(nèi)容,多占用一些內(nèi)存。那么就會(huì)存在浪費(fèi)內(nèi)存的問題,因?yàn)槎褩#ㄗ晕冶容^模糊的概念)所指的地址不在同一個(gè)地址。

有沒有一種解決辦法 是讓這個(gè)方法在一個(gè)同樣的內(nèi)存,而實(shí)例對(duì)象從這個(gè)方法上去訪問、繼承。答案在下面

3.prototype

Javascript規(guī)定,每一個(gè)構(gòu)造函數(shù)都有一個(gè)prototype屬性(只有函數(shù)具有prototype屬性,并且當(dāng)作為構(gòu)造函數(shù)調(diào)用某個(gè)函數(shù)時(shí),該函數(shù)使用該屬性創(chuàng)建新對(duì)象),指向另一個(gè)對(duì)象。這個(gè)對(duì)象的所有屬性和方法,都會(huì)被構(gòu)造函數(shù)的實(shí)例繼承(也就是說可以訪問到,且地址都是同一個(gè)地址)。

js為了配合prototype屬性,有以下輔助方法來查看原型對(duì)象和實(shí)例對(duì)象的關(guān)系

isPrototypeOf()這個(gè)方法用來判斷,某個(gè)prototype對(duì)象和某個(gè)實(shí)例之間的關(guān)系。

console.log(Cat.prototype.isPrototypeOf(cat1))? // 輸出為true

hasOwnProperty()每個(gè)實(shí)例對(duì)象都有一個(gè)hasOwnProperty()方法,用來判斷某一個(gè)屬性到底是本地屬性,還是繼承prototype對(duì)象的屬性。

console.log(cat1.hasOwnProperty("name"))//true

console.log(cat1.hasOwnProperty("type"))//false

4.繼承

4.1構(gòu)造函數(shù)綁定

使用call或apply方法,將父對(duì)象的構(gòu)造函數(shù)綁定在子對(duì)象上

如何讓貓來繼承動(dòng)物這個(gè)屬性呢


只需要添加一個(gè)apply

4.2利用prototype屬性

如果Cat的prototype屬性指向Animal的實(shí)例,那么Cat的所有實(shí)例都能繼承Animal

因?yàn)槊總€(gè)構(gòu)造函數(shù)都有一個(gè)prototype對(duì)象指向一個(gè)地址,他們的實(shí)例都能夠去訪問并且繼承。(實(shí)例的constructor是指向原型對(duì)象)

Cat.prototype = new Animal(); 這一行代碼的意思是將Cat的prototype對(duì)象只想了Animal的實(shí)例,也將之前Cat的prototype對(duì)象完全刪除,賦予了一個(gè)新的值

Cat.prototype.constructor = Cat; 這一行代碼的意思是 任何一個(gè)prototype對(duì)象都有一個(gè)constructor屬性指向它的構(gòu)造函數(shù)(意味著cat1.constructor是指向Cat的,而Cat又指向了Animal),如果沒有“Cat.prototype = new Animal();?”? 那么Cat.prototype.constructor是指向Cat的,但是加了那一行就指向了Animal? console.log(Cat.prototype.constructor == Animal)為true,這樣顯然會(huì)導(dǎo)致繼承鏈的紊亂(cat1明明是用構(gòu)造函數(shù)Cat生成的)。

4.3直接繼承prototype

第三種方法是對(duì)第二種方法的改進(jìn),在Animal對(duì)象中不變的屬性可以寫入到prototype屬性中,所以我們可以讓Cat()直接跳過Animal()去繼承Animal.prototype

缺點(diǎn)也很明顯,如果對(duì)Cat.prototype的修改也會(huì)修改掉Animal.prototype因?yàn)镃at.prototype.constructor=Cat,

此時(shí)是指向Animal的。比如console.log(Animal.prototype.constructor) 打印結(jié)果為Cat

4.4利用空對(duì)象作為一個(gè)中介

因?yàn)樯鲜龅娜秉c(diǎn) 所以可以利用一個(gè)空對(duì)象來作為一個(gè)中介,因?yàn)榭諏?duì)象幾乎是不占內(nèi)存的。

打印結(jié)果如下

5.非構(gòu)造函數(shù)的繼承

如果說是兩個(gè)普通的對(duì)象,而非構(gòu)造函數(shù),比如有一個(gè)Chinese對(duì)象和Doctor,如何讓Doctor去繼承Chinese的china屬性值呢?

5.1object函數(shù)

可以利用object()函數(shù)

打印結(jié)果為 china

其實(shí)object()函數(shù)就做了一件事情,將子對(duì)象的prototype屬性指向了父對(duì)象,這樣子對(duì)象就能夠訪問父對(duì)象的屬性和方法了,object函數(shù)return的一個(gè)構(gòu)造函數(shù),這樣換算的結(jié)果和之前的一樣。

5.2淺拷貝

這樣的拷貝其實(shí)是有問題的,如果父對(duì)象的屬性為一個(gè)數(shù)組或者是另外一個(gè)對(duì)象,那么實(shí)際上子對(duì)象獲得的只是一個(gè)內(nèi)存地址,修改子對(duì)象的屬性和屬性值,父對(duì)象也會(huì)發(fā)生修改。而沒有完成真正的拷貝,如果給Chinese添加一個(gè)“出生地”的屬性,為一個(gè)數(shù)組的話

所以,extendCopy()只是拷貝基本類型的數(shù)據(jù),我們把這種拷貝叫做"淺拷貝"。

5.3深拷貝

所謂"深拷貝",就是能夠?qū)崿F(xiàn)真正意義上的數(shù)組和對(duì)象的拷貝。它的實(shí)現(xiàn)并不難,只要遞歸調(diào)用"淺拷貝"就行了。

因?yàn)楫?dāng)遍歷到birthPlaces的時(shí)候就會(huì)遞歸再次調(diào)用deepCopy函數(shù),所以console.log(c)會(huì)有兩次打印的結(jié)果。



以上內(nèi)容均來自于阮一峰老師,且經(jīng)過測試。

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

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

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