原型鏈一直是個很抽象的概念,看不到,摸不著.隨著最近對JavaScript進一步的學習,我對原型鏈有了一點理解,下面講出來.
基礎知識
在JavaScript中,一共有兩種類型的值,原始值和對象值.每個對象都有一個內部屬性[[prototype]],我們通常稱之為原型.原型的值可以是一個對象,也可以是null.如果它的值是一個對象,則這個對象也一定有自己的原型.這樣就形成了一條線性鏈,我們稱之為原型鏈.
訪問一個對象的原型可以使用ES5中的Object.getPrototypeOf方法,或者ES6中的__proto__屬性.
原型鏈的作用是用來實現繼承,比如我們建立一個數組,數組的方法就是從數組的原型上繼承而來的.
var arr = [];
arr.map === Array.prototype.map //arr.map是從arr.__proto__上繼承下來的,arr.__proto__也就是Array.prototype
圖形化原型鏈
雖然我們都說"原型鏈",但實際上,在不考慮網頁中frame的情況,js引擎在執行期間的某一時刻,所有存在的對象組成的是一棵原型樹.預設情況下,只有一棵樹.根節點可以說是Object.prototype,也可以說是null.
但我們可以再建立一棵原型樹,通過使用Object.create方法
var foo = Object.create(null); //foo是一個對象,但它是游離的,不屬於已有的那棵原型樹var bar = Object.create(foo); //bar的原型是foovar baz = Object.create(foo); //baz的原型是foo
這樣我們有了第二棵原型樹
遍曆原型鏈
我們沒有辦法遍曆到所有以某個對象為原型的對象,但我們可以向上遍曆,擷取到一個對象所有的上層原型,這個原型鏈必定是線性,盡頭是null.
function getPrototypeChain(object) { var protoChain = []; while (object = object.__proto__) { protoChain.push(object); } protoChain.push(null); return protoChain;}
實驗一下,不同的環境實現不同,顯示形式也不同.下面是在chrome控制台中的顯示.
>getPrototypeChain(new String(""))[String, Object, null] //依次是String.prototype,Object.prototype,null
>getPrototypeChain(function(){})[function Empty() {}, Object, null] //依次是Function.prototype,Object.prototype,null
內建類型的對象的原型鏈並不長,下面試試宿主對象.
>getPrototypeChain(document.createElement("div"))[HTMLDivElement, HTMLElement, Element, Node, Object, null]
這個就長多了.
超長原型鏈
可以看出來,我們平時使用的對象並沒有很長的原型鏈.但可以自己構造一個.
function Foo() {}for (var i = 0; i < 100; i++) { Foo.prototype["prop" + i] = i; Foo.prototype = new Foo;}console.dir(getPrototypeChain(new Foo));
最後的這個new Foo有多少個上層原型呢?