您好,登錄后才能下訂單哦!
大家可以先仔細分析下該圖,然后讓我們進入主題
prototype
首先來介紹下 prototype
屬性。這是一個顯式原型屬性,只有函數才擁有該屬性。基本上所有函數都有這個屬性,但是也有一個例外
let fun = Function.prototype.bind()
如果你以上述方法創建一個函數,那么可以發現這個函數是不具有 prototype
屬性的。
當我們聲明一個函數時,這個屬性就被自動創建了。
function Foo() {}
并且這個屬性的值是一個對象(也就是原型),只有一個屬性 constructor
constructor
對應著構造函數,也就是 Foo
。
constructor
是一個公有且不可枚舉的屬性。一旦我們改變了函數的 prototype
,那么新對象就沒有這個屬性了(當然可以通過原型鏈取到 constructor
)。
那么你肯定也有一個疑問,這個屬性到底有什么用呢?其實這個屬性可以說是一個歷史遺留問題,在大部分情況下是沒用的,在我的理解里,我認為他有兩個作用:
讓實例對象知道是什么函數構造了它
如果想給某些類庫中的構造函數增加一些自定義的方法,就可以通過 xx.constructor.method
來擴展
_proto_
這是每個對象都有的隱式原型屬性,指向了創建該對象的構造函數的原型。其實這個屬性指向了 [[prototype]],但是 [[prototype]] 是內部屬性,我們并不能訪問到,所以使用 _proto_
來訪問。
因為在 JS 中是沒有類的概念的,為了實現類似繼承的方式,通過 _proto_
將對象和原型聯系起來組成原型鏈,得以讓對象可以訪問到不屬于自己的屬性。
_proto_
如何產生的從上圖可知,當我們使用 new
操作符時,生成的實例對象擁有了 _proto_
屬性。
function Foo() {}// 這個函數是 Function 的實例對象// function 就是一個語法糖// 內部調用了 new Function(...)
所以可以說,在 new
的過程中,新對象被添加了 _proto_
并且鏈接到構造函數的原型上。
新生成了一個對象
鏈接到原型
綁定 this
返回新對象
在調用 new
的過程中會發生以上四件事情,我們也可以試著來自己實現一個 new
function create() { // 創建一個空的對象 let obj = new Object() // 獲得構造函數 let Con = [].shift.call(arguments) // 鏈接到原型 obj.__proto__ = Con.prototype // 綁定 this,執行構造函數 let result = Con.apply(obj, arguments) // 確保 new 出來的是個對象 return typeof result === 'object' ? result : obj }
對于實例對象來說,都是通過 new
產生的,無論是 function Foo()
還是 let a = { b : 1 }
。
對于創建一個對象來說,更推薦使用字面量的方式創建對象。因為你使用 new Object()
的方式創建對象需要通過作用域鏈一層層找到 Object
,但是你使用字面量的方式就沒這個問題。
function Foo() {}// function 就是個語法糖// 內部等同于 new Function()let a = { b: 1 }// 這個字面量內部也是使用了 new Object()
對于對象來說,xx.__proto__.contrcutor
是該對象的構造函數,但是在圖中我們可以發現 Function.__proto__ === Function.prototype
,難道這代表著 Function
自己產生了自己?
答案肯定是否認的,要說明這個問題我們先從 Object
說起。
從圖中我們可以發現,所有對象都可以通過原型鏈最終找到 Object.prototype
,雖然 Object.prototype
也是一個對象,但是這個對象卻不是 Object
創造的,而是引擎自己創建了 Object.prototype
。所以可以這樣說,所有實例都是對象,但是對象不一定都是實例。
接下來我們來看 Function.prototype
這個特殊的對象,如果你在瀏覽器將這個對象打印出來,會發現這個對象其實是一個函數。
我們知道函數都是通過 new Function()
生成的,難道 Function.prototype
也是通過 new Function()
產生的嗎?答案也是否定的,這個函數也是引擎自己創建的。首先引擎創建了 Object.prototype
,然后創建了 Function.prototype
,并且通過 __proto__
將兩者聯系了起來。這里也很好的解釋了上面的一個問題,為什么 let fun = Function.prototype.bind()
沒有 prototype
屬性。因為 Function.prototype
是引擎創建出來的對象,引擎認為不需要給這個對象添加 prototype
屬性。
所以我們又可以得出一個結論,不是所有函數都是 new Function()
產生的。
有了 Function.prototype
以后才有了 function Function()
,然后其他的構造函數都是 function Function()
生成的。
現在可以來解釋 Function.__proto__ === Function.prototype
這個問題了。因為先有的 Function.prototype
以后才有的 function Function()
,所以也就不存在雞生蛋蛋生雞的悖論問題了。對于為什么 Function.__proto__
會等于 Function.prototype
,個人的理解是:其他所有的構造函數都可以通過原型鏈找到 Function.prototype
,并且 function Function()
本質也是一個函數,為了不產生混亂就將 function Function()
的 __proto__
聯系到了 Function.prototype
上。
Object
是所有對象的爸爸,所有對象都可以通過 __proto__
找到它
Function
是所有函數的爸爸,所有函數都可以通過 __proto__
找到它
Function.prototype
和 Object.prototype
是兩個特殊的對象,他們由引擎來創建
除了以上兩個特殊對象,其他對象都是通過構造器 new
出來的
函數的 prototype
是一個對象,也就是原型
對象的 __proto__
指向原型, __proto__
將對象和原型連接起來組成了原型鏈
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。