JavaScript中的原型繼承基礎(chǔ)學(xué)習(xí)教程
來源:易賢網(wǎng) 閱讀:694 次 日期:2016-07-02 13:19:05
溫馨提示:易賢網(wǎng)小編為您整理了“JavaScript中的原型繼承基礎(chǔ)學(xué)習(xí)教程”,方便廣大網(wǎng)友查閱!

這篇文章主要介紹了JavaScript中的原型繼承基礎(chǔ)學(xué)習(xí)教程,基于原型prototype的繼承是JavaScript中實(shí)現(xiàn)面向?qū)ο笾械睦^承特性的基本手段,需要的朋友可以參考下

大多數(shù)編程語言中,都有類和對(duì)象,一個(gè)類可以繼承其他類。

在JavaScript中,繼承是基于原型的(prototype-based),這意味著JavaScript中沒有類,取而代之的是一個(gè)對(duì)象繼承另一個(gè)對(duì)象。:)

1. 繼承, the proto

在JavaScript中,當(dāng)一個(gè)對(duì)象rabbit繼承另一了對(duì)象animal時(shí),這意味著rabbit對(duì)象中將會(huì)有一個(gè)特殊的屬性:rabbit.__proto__ = animal;

當(dāng)訪問rabbit對(duì)象時(shí),如果解釋器在rabbit中不能找到屬性,那么它會(huì)順著__proto__鏈往上在animal對(duì)象中尋找

栗子中的__proto__屬性僅在Chrome和FireFox中可以訪問,請(qǐng)看一個(gè)栗子:

var animal = { eats: true }

var rabbit = { jumps: true }

rabbit.__proto__ = animal // inherit

alert(rabbit.eats) // true

eats屬性是從animal對(duì)象中訪問的。

如果在rabbit對(duì)象中已經(jīng)發(fā)現(xiàn)了屬性,那么就不會(huì)去檢查proto屬性啦。

再來一個(gè)栗子,當(dāng)子類中也有eats屬性時(shí),父類中的就不會(huì)訪問了。

var animal = { eats: true }

var fedUpRabbit = { eats: false}

fedUpRabbit.__proto__ = animal 

alert(fedUpRabbit.eats) // false

你也可以在animal中添加一個(gè)函數(shù),那么在rabbit中也可以訪問了。

var animal = {

 eat: function() {

  alert( "I'm full" )

  this.full = true

 }

}

var rabbit = {

 jump: function() { /* something */ }

}

rabbit.__proto__ = animal 

(1)rabbit.eat():

rabbit.eat()函數(shù)以如下兩步執(zhí)行:

首先,解釋器查找rabbit.eat,rabbit中沒有eat函數(shù),那么它就順著rabbit.__proto__往上找,在animal中找到了。

函數(shù)以this = rabbit運(yùn)行。this值與__proto__屬性完全無關(guān)。

因此,this.full = true在rabbit中:

看看這里我們有什么新發(fā)現(xiàn),一個(gè)對(duì)象調(diào)用了父類函數(shù),但是this還是指向?qū)ο蟊旧?,這就是繼承。

被__proto__引用的對(duì)象稱作是原型(prototype),animal是rabbit的原型(譯者注:這就是rabbit的__proto__屬性引用了animal 的prototype屬性)

(2)讀時(shí)查找,不是寫時(shí)

當(dāng)讀取一個(gè)對(duì)象時(shí),比如this.prop,解釋器會(huì)在它的原型中查找屬性。

當(dāng)設(shè)置一個(gè)屬性值時(shí),比如this.prop = value,那么就沒有理由去查找了,這個(gè)屬性(prop)會(huì)被直接添加到這個(gè)對(duì)象中(這里是this)。delete obj.prop也類似,它只刪除對(duì)象本身的屬性,原型中的屬性保持原封不動(dòng)。

(3)關(guān)于proto

如果你在閱讀指南,這里我們叫的__proto__,在指南中表示為[[Prototype]]。雙方括號(hào)是很重要的,因?yàn)橛辛硪粋€(gè)屬性叫做prototype。

2. Object.create, Object.getPrototypeOf

__proto__是一個(gè)非標(biāo)準(zhǔn)的屬性,由Chrome/FireFox提供訪問,在其他的瀏覽器中保持不可見。

所有的現(xiàn)代瀏覽器除了Opera(IE > 9)支持兩個(gè)標(biāo)準(zhǔn)的函數(shù)來處理原型問題:

Object.ceate(prop[,props])

用給定了proto創(chuàng)建一個(gè)空對(duì)象:

var animal = { eats: true }

rabbit = Object.create(animal)

alert(rabbit.eats) // true

上面代碼創(chuàng)建了一個(gè)空rabbit對(duì)象,并且原型設(shè)置為animal

rabbit對(duì)象創(chuàng)建好以后,我們可以往里添加屬性了:

var animal = { eats: true }

rabbit = Object.create(animal)

rabbit.jumps = true

Object.creat函數(shù)的第二個(gè)參數(shù)props是可選的,它允許像新對(duì)象設(shè)置屬性。這里就省略了,因?yàn)槲覀冴P(guān)系的繼承。

(1)Object.getPrototypeOf(obj)

返回obj.__proto__的值。這個(gè)函數(shù)是標(biāo)準(zhǔn)的,可以在不能直接訪問__proto__屬性的瀏覽器中使用了。

var animal = {

 eats: true

}

rabbit = Object.create(animal)

alert( Object.getPrototypeOf(rabbit) === animal ) // true

現(xiàn)代瀏覽器允許讀取__proto__屬性值,但是不能設(shè)置。

3. The prototype

有一些好的跨瀏覽器的方式設(shè)置__proto__屬性,這將會(huì)使用構(gòu)造器函數(shù)(constructor functions)。記住!任何函數(shù)創(chuàng)建一個(gè)對(duì)象都是通過new關(guān)鍵字的。

一個(gè)栗子:

function Rabbit(name) {

 this.name = name

}

var rabbit = new Rabbit('John')

alert(rabbit.name) // John

new操作將原型的屬性設(shè)置到rabbit對(duì)象的的__proto__屬性中了。

讓我們來看看它的原理,例如,new Rabbit 對(duì)象,而Rabbit是繼承animal 的。

var animal = { eats: true }

function Rabbit(name) {

 this.name = name

}

Rabbit.prototype = animal

var rabbit = new Rabbit('John')

alert( rabbit.eats ) // true, because rabbit.__proto__ == animal

Rabbit.prototype = animal 字面量意味著:對(duì)所有由new Rabbit創(chuàng)建的對(duì)象設(shè)__proto__ = animal

4. 跨瀏覽器 Object.create(proto)

Object.create(prop)函數(shù)功能的強(qiáng)大的,因?yàn)樗试S從給定的對(duì)象直接繼承。它可以由如下代碼模擬:

function inherit(proto) {

 function F() {}

 F.prototype = proto

 return new F

}

inherit(animal) 與Object.create(animal)是完全等同的,返回一個(gè)空的對(duì)象,并且object.__proto__ = animal。

一個(gè)栗子:

var animal = { eats: true }

var rabbit = inherit(animal)

alert(rabbit.eats) // true

alert(rabbit.hasOwnProperty('eats')) // false, from prototype

來看一下它的原理是什么:

function inherit(proto) {

 function F() {}   // (1)

 F.prototype = proto // (2)

 return new F()   // (3)

}

(1) 創(chuàng)建了一個(gè)新函數(shù),函數(shù)沒有向this設(shè)置任何屬性,以此`new F` 會(huì)創(chuàng)建一個(gè)空對(duì)象。

(2) `F.prototype`被設(shè)置為proto

(3) `new` F創(chuàng)建了一個(gè)空對(duì)象,對(duì)象的`__proto__ = F.prototype` 

(4) Bingo! 我們得到了一個(gè)繼承`proto`的空對(duì)象

這個(gè)函數(shù)廣泛適用于各種庫和框架之中。

你的函數(shù)接受了一個(gè)帶有options 的對(duì)象

/* options contains menu settings: width, height etc */

function Menu(options) {

 // ...

}

你想設(shè)置某些options

function Menu(options) {

 options.width = options.width || 300 // set default value

 // ...

}

。。。但是改變參數(shù)值可能會(huì)產(chǎn)生一些錯(cuò)誤的結(jié)果,因?yàn)閛ptions可能會(huì)在外部代碼中使用。一個(gè)解決辦法就是克隆options對(duì)象,復(fù)制所有的屬性到一個(gè)新的對(duì)象中,在新對(duì)象中修改,

怎樣用繼承來解決這個(gè)問題呢? P.S. options可以添加設(shè)設(shè)置,但是不能被刪除。

Solution

你可以繼承options,并且在它的子類的中修改或者添加新的屬性。

function inherit(proto) {

 function F() {}

 F.prototype = proto

 return new F

}

function Menu(options) {

 var opts = inherit(options)

 opts.width = opts.width || 300

 // ...

}

所有的操作只在子對(duì)象中有效,當(dāng)Menu方法結(jié)束時(shí),外部代碼仍然可以使用沒有修改的過的options對(duì)象。delete操作在這里非常重要,如果width是一個(gè)prototype中的屬性,delete opts.width不會(huì)產(chǎn)生任何作用

5. hasOwnProperty

所有的對(duì)象都有hasOwnProperty函數(shù),它可以用來檢測(cè)一個(gè)屬性是否對(duì)象自身還是屬于原型

一個(gè)栗子:

function Rabbit(name) {

 this.name = name

}

Rabbit.prototype = { eats: true }

var rabbit = new Rabbit('John')

alert( rabbit.hasOwnProperty('eats') ) // false, in prototype

alert( rabbit.hasOwnProperty('name') ) // true, in object

6. Looping with/without inherited properties

for..in循環(huán)輸出一個(gè)對(duì)象的所有屬性,包括自身的和原型的。

function Rabbit(name) {

 this.name = name

}

Rabbit.prototype = { eats: true }

var rabbit = new Rabbit('John')

for(var p in rabbit) {

 alert (p + " = " + rabbit[p]) // outputs both "name" and "eats"

}

用hasOwnProperty可以過濾得到屬于對(duì)象自己的屬性:

function Rabbit(name) {

 this.name = name

}

Rabbit.prototype = { eats: true }

var rabbit = new Rabbit('John')

for(var p in rabbit) {

 if (!rabbit.hasOwnProperty(p)) continue // filter out "eats"

 alert (p + " = " + rabbit[p]) // outputs only "name"

}

7. Summary

JavaScript是通過一個(gè)特殊的屬性proto來實(shí)現(xiàn)繼承的

當(dāng)訪問一個(gè)對(duì)象的屬性時(shí),如果解釋器不能在對(duì)象中找到,它就會(huì)去對(duì)象的原型中繼續(xù)尋找 對(duì)函數(shù)屬性來說,this指向這個(gè)對(duì)象,而不是它的原型。

賦值obj.prop = value, 刪除delete obj.prop

管理proto:

Chrome和FireFox可以直接訪問對(duì)象的__proto__屬性,大多數(shù)現(xiàn)代瀏覽器支持用Object.getPrototypeOf(obj)只讀訪問。

Object.create(proto) 可以用給定的proto生成空的子對(duì)象,或者通過如下代碼達(dá)到相同的功能:

function inherit(proto) {

   function F() {}   

   F.prototype = proto

   return new F()  

  }

其他方法:

for..in循環(huán)輸出一個(gè)對(duì)象的所有屬性(包括自身的和原型的)和對(duì)象的原型鏈。

如果一個(gè)屬性prop屬于對(duì)象obj那么obj.hasOwnProperty(prop)返回true,否則返回false。

更多信息請(qǐng)查看網(wǎng)絡(luò)編程
易賢網(wǎng)手機(jī)網(wǎng)站地址:JavaScript中的原型繼承基礎(chǔ)學(xué)習(xí)教程
由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢回復(fù)僅供參考,敬請(qǐng)考生以權(quán)威部門公布的正式信息和咨詢?yōu)闇?zhǔn)!

2025國考·省考課程試聽報(bào)名

  • 報(bào)班類型
  • 姓名
  • 手機(jī)號(hào)
  • 驗(yàn)證碼
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡(jiǎn)要咨詢 | 簡(jiǎn)要咨詢須知 | 新媒體/短視頻平臺(tái) | 手機(jī)站點(diǎn) | 投訴建議
工業(yè)和信息化部備案號(hào):滇ICP備2023014141號(hào)-1 云南省教育廳備案號(hào):云教ICP備0901021 滇公網(wǎng)安備53010202001879號(hào) 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號(hào)
云南網(wǎng)警備案專用圖標(biāo)
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關(guān)注公眾號(hào):hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權(quán)所有:易賢網(wǎng)
云南網(wǎng)警報(bào)警專用圖標(biāo)