天天看點

JS原型鍊

JS每個對象都有一個内部屬性[[prototype]],我們通常稱之為原型.原型的值可以是一個對象,也可以是null.如果它的值是一個對象,則這個對象也一定有自己的原型.這樣就形成了一條線性的鍊,我們稱之為原型鍊。

通路一個對象的原型可以使用ES5中的Object.getPrototypeOf方法,或者ES6中的__proto__屬性。

原型鍊的作用是用來實作繼承,比如我們建立一個數組,數組的方法就是從數組的原型上繼承而來的。

在JavaScript中,每個函數 都有一個prototype屬性,當一個函數被用作構造函數來建立執行個體時,這個函數的prototype屬性值會被作為原型指派給所有對象執行個體(也就是設定 執行個體的`__proto__`屬性),也就是說,所有執行個體的原型引用的是函數的prototype屬性。

在JavaScript的原型對象中,還包含一個”constructor”屬性,這個屬性對應建立所有指向該原型的執行個體的構造函數。

”Object.prototype”的值就是”Object {}”這個原型對象。反過來,當通路”Object.prototype”對象的”constructor”這個屬性的時候,就得到了Obejct函數。

另外,當通過”Object.prototype._proto_”擷取Object原型的原型的時候,将會得到”null”,也就是說”Object {}”原型對象就是原型鍊的終點了。

Function對象作為一個函數,就會有prototype屬性,該屬性将對應”function () {}”對象。

Function對象作為一個對象,就有__proto__屬性,該屬性對應”Function.prototype”,也就是說,”Function._proto_ === Function.prototype”。

幾點了解

1.Object.__proto__ === Function.prototype // true

  Object是函數對象,是通過new Function()建立,是以Object.__proto__指向Function.prototype。

2.Function.__proto__ === Function.prototype // true

  Function 也是對象函數,也是通過new Function()建立,是以Function.__proto__指向Function.prototype。

3.Function.prototype.__proto__ === Object.prototype //true

Function.prototype是個函數對象,理論上他的__proto__應該指向 Function.prototype,就是他自己,自己指向自己,沒有意義,指向Object.prototype,Object.prototype.__proto__ === null,保證原型鍊能夠正常結束。

周遊原型鍊

我們沒有辦法周遊到所有以某個對象為原型的對象,但我們可以向上周遊,擷取到一個對象所有的上層原型,這個原型鍊必定是線性的,盡頭是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["foo" + i] = i;

    Foo.prototype = new Foo;

console.dir(getPrototypeChain(new Foo));

繼續閱讀