1. 程式人生 > >js原型鏈(看了一個大神 的部落格,覺得真的是挖到了寶藏一樣)

js原型鏈(看了一個大神 的部落格,覺得真的是挖到了寶藏一樣)

原型的基本概念


要想真正理解js的原型和原型鏈的概念,必須且只要記住以下幾點即可:

▶ 一切都是物件(看似如此)。

undefined, number, string, boolean四種屬於簡單的值型別,不是物件,使用基本型別變數可以呼叫方法是因為產生了包裝物件(臨時的)。剩下的幾種情況——函式、陣列、物件、null、new Number(10)都是物件,他們都是引用型別。

 所有的物件都是由函式建立。

1、函式也是一個物件,由Function函式建立。

2、var obj = { a: 10, b: 20}; var arr = [5, 'x',true]; 這類定義其實只是一個下面的語法糖而已

3、Function也是一個物件,由它自己建立,有趣吧

所有的函式都有prototype屬性(原型)

注意,是函式才有prototype,普通物件沒有。

函式建立時就自動帶有這個屬性,也就是我們講的“原型”,這也絕對是js中最基礎也是最難的部分。

這個prototype的屬性值是一個物件(屬性的集合,再次強調!),預設的只有一個叫做constructor的屬性,指向這個函式本身。

prototype可以新增自定義屬性,你可以試試Object.prototype,可以看到很多自定義的屬性:

所有的物件都有__proto__。

1、所有的物件都有__proto__,指向建立它的函式的prototype,注意,你要這樣來理解這句話的意思,那就是同一個函式new出來的物件的__proto__都統一指向了這個函式的prototype,根據後面要講述的原型鏈規則,也就是說通過這個函式new出來的所有物件都可以直接使用該函式原型上的任意屬性和方法!,

因此,對於jquery的這種形式就應該能理解了

$是jQuery的簡寫別名,其實是一個函式。因此$div是jQuery函式建立的物件,很顯然,on方法就是在jQuery.prototype上定義的屬性(函式),因此所有jQuery函式建立的物件都已直接使用on方法

2、所有的函式,比如 function fn(){},都是由Function函式建立,因此fn的__proto__指向Function的prototype。

 

3、比較有意思的是,Function也是函式,因此它也由Function建立的,也就是說它自己建立了自己!所有Function的__proto__指向的就是Function的prototype!

4、同理,Object函式也是由Function建立,因此Object的__proto__同樣指向Function的prototype!

5、prototype也是一個物件,原始prototype只有一個叫做constructor的屬性,指向這個函式本身。因為prototype是一個物件,因此它也是由Object方法建立,因此它的__proto__將指向Object.prototype,如下所示:

6、但是Object.prototype卻是一個特例——它的__proto__指向的是null,切記切記!

想想也覺得應該是這樣吧

因此,根據上面的幾條基本概念,從這段簡單的程式碼我們可以畫出這樣一條關係鏈圖:

 

 

原型鏈


以上圖為例,我們來對原型鏈進行描述。

首先person是個函式,我們在它的原型(prototype)上添加了一個getName的方法(函式屬性)

然後zs是person new出來的一個物件,因此zs的__proto__指向person的prototype。

person.prototype作為一個普通物件,是有Object函式建立的,因此它的__proto__指向Object.prototype

我們看到,zs物件本身沒有getName方法,那它是怎麼訪問到的?

原來在當前物件中沒有找到某個屬性時,它會順著__proto__屬性依次向上查詢,知道找到為止!因此,

getName屬性在zs物件中沒有找到,就會繼續找zs.__proto__,也就是person.prototype,很顯然,這裡找到了,就不會再向上查找了

hasOwnProperty屬性顯然zs物件中沒有找到,就會繼續找zs.__proto__,也就是person.prototype,很顯然,person.prototype中也找不到,於是繼續向上在person.prototype.__proto__中找。person.prototype是一個普通物件,它是由Object方法建立的,因此person.prototype.__proto__就是Object.prototype,很顯然,Object.prototype裡面已經定義了hasOwnProperty方法(屬性),因此在這裡也找到了。

上面這種查詢形式就成為原型鏈。就像一根鏈條一樣,依次向上連結起來。這也是ES5及之前的所謂“繼承”實現。

原型鏈訪問順序

我們注意到,在getName方法中是直接使用this.name來獲取zs物件的name值得,這就是說js在訪問原型物件的方法時,直接把當前物件應用到了這個方法的上下文中。也就是相當於:person.prototype.getName.apply(zs)

總結


要想正確理解掌握原型和原型鏈的概念,必須把上面講的最核心和基本的幾個概念理解和記住,否則看再多的案例也只會雲裡霧裡,暈暈乎乎的,越加無法理解,靠死記硬背肯定是不行的。並且只要熟練掌握和牢記上面說的這幾個概念,不管遇到任何變著花樣的原型考查,都一定能夠正確理解。