在javascript中,prototype、constructor以及__proto__之間有著「著名」的剪不斷理還亂的三角關係,以下由我帶領大家詳細講解這些關係。
javascript裡的關係又多又亂。作用域鍊是一種單向的鍊式關係,還算簡單清晰;this機制的呼叫關係,稍微有些複雜;而關於原型,則是prototype、proto和constructor的三角關係。本文先用一張圖開宗明義,然後詳細解釋原型的三角關係
圖示
#概念
## 上圖中的複雜關係,實際上來源就兩行程式碼function Foo(){};var f1 = new Foo;【建構子】 用來初始化新建立的物件的函數是建構子。在範例中,Foo()函數是建構子【實例物件】 透過建構函式的new操作所建立的物件是實例物件。可以用一個建構函數,建構多個實例物件
function Foo(){}; var f1 = new Foo; var f2 = new Foo; console.log(f1 === f2);//false【原型物件及prototype】 建構子有一個prototype屬性,指向實例物件的原型物件。透過同一個建構函數實例化的多個物件具有相同的原型物件。常使用原型物件來實作繼承
function Foo(){}; Foo.prototype.a = 1; var f1 = new Foo; var f2 = new Foo;console.log(Foo.prototype.a); //1 console.log(f1.a);//1 console.log(f2.a);//1【constructor】 原型物件有一個constructor屬性,指向該原型物件對應的建構子
function Foo(){}; console.log(Foo.prototype.constructor === Foo);//true由於實例物件可以繼承原型物件的屬性,所以實例物件也擁有constructor屬性,同樣指向原型物件對應的建構子
function Foo(){}; var f1 = new Foo; console.log(f1.constructor === Foo);//true【proto】 實例物件有一個proto屬性,指向該實例物件對應的原型物件
function Foo(){}; var f1 = new Foo; console.log(f1.__proto__ === Foo.prototype);//true
說明
概念介紹完了,現在對圖示的關係進行詳細說明function Foo(){}; var f1 = new Foo;【第一部分:Foo】
實例物件f1是透過建構子Foo()的new操作建立的。建構子Foo()的原型物件是Foo.prototype;實例物件f1透過__proto__屬性也指向原型物件Foo.prototype
function Foo(){}; var f1 = new Foo; console.log(f1.__proto === Foo.prototype);//true實例物件f1本身並沒有constructor屬性,但它可以繼承原型物件Foo.prototype的constructor屬性
function Foo(){}; var f1 = new Foo;console.log(Foo.prototype.constructor === Foo);//true console.log(f1.constructor === Foo);//true console.log(f1.hasOwnProperty('constructor'));//false下圖是實例物件f1的控制台效果 【第二部分: Object】
Foo.prototype是f1的原型對象,同時它也是實例對象。實際上,任何物件都可以看做是透過Object()建構子的new操作實例化的對象 所以,Foo.prototype作為實例對象,它的建構子是Object(),原型對像是Object.prototype。對應地,建構子Object()的prototype屬性指向原型物件Object;實例物件Foo.prototype的proto屬性同樣指向原型物件Object
function Foo(){}; var f1 = new Foo; console.log(Foo.prototype.__proto__ === Object.prototype);//true實例物件Foo.prototype本身俱有constructor屬性,所以它會覆寫繼承自原型物件Object.prototype的constructor屬性
function Foo(){}; var f1 = new Foo; console.log(Foo.prototype.constructor === Foo);//true console.log(Object.prototype.constructor === Object);//true console.log(Foo.prototype.hasOwnProperty('constructor'));//true下圖是實例物件Foo.prototype的控制台效果
如果Object.prototype作為實例物件的話,其原型物件是什麼,結果是null。私以為,這可能也是typeof null的結果是'object'的原因之一吧
console.log(Object.prototype.__proto__ === null);//true#【第三部分: Function】
## 前面已經介紹過,函數也是對象,只不過是有特殊功能的對象而已。任何函數都可以看做是透過Function()建構子的new操作實例化的結果
如果把函數Foo當成實例物件的話,其建構子是Function(),其原型物件是Function.prototype ;類似地,函式Object的建構子也是Function(),其原型物件是Function.prototype
function Foo(){}; var f1 = new Foo;console.log(Foo.__proto__ === Function.prototype);//true console.log(Object.__proto__ === Function.prototype);//true
原型物件Function.prototype的constructor屬性指向建構函式Function();實例物件Object和Foo本身沒有constructor屬性,需要繼承原型物件Function.prototype的constructor屬性
function Foo(){}; var f1 = new Foo; console.log(Function.prototype.constructor === Function);//true console.log(Foo.constructor === Function);//true console.log(Foo.hasOwnProperty('constructor'));//false console.log(Object.constructor === Function);//true console.log(Object.hasOwnProperty('constructor'));//false
所有的函數都可以看成是建構子Function()的new操作的實例化物件。那麼,Function可以看成是呼叫其自身的new操作的實例化的結果
所以,如果Function作為實例對象,其構造函數是Function,其原型對像是Function.prototype
console.log(Function.__proto__ === Function.prototype);//true console.log(Function.prototype.constructor === Function);//true console.log(Function.prototype === Function);//true
如果Function.prototype作為實例物件的話,其原型物件是什麼呢?和前面一樣,所有的物件都可以看成是Object()建構子的new操作的實例化結果。所以,Function.prototype的原型物件是Object.prototype,其原型函數是Object()
console.log(Function.prototype.__proto__ === Object.prototype);//true
第二部分介紹過,Object.prototype的原型物件是null
console.log(Object.prototype.__proto__ === null);//true
总结
【1】函数(Function也是函数)是new Function的结果,所以函数可以作为实例对象,其构造函数是Function(),原型对象是Function.prototype
【2】对象(函数也是对象)是new Object的结果,所以对象可以作为实例对象,其构造函数是Object(),原型对象是Object.prototype
【3】Object.prototype的原型对象是null
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
以上是圖解prototype、proto和constructor的三角關係的詳細內容。更多資訊請關注PHP中文網其他相關文章!