昨天看了大牛的這篇關(guān)于模擬bind函數(shù)實(shí)現(xiàn)的文章庸追,深受啟發(fā)摆霉。其中有一處涉及到關(guān)于bind方法返回的函數(shù)作為構(gòu)造函數(shù)的問題令我百思不得其解涧黄。于是決定補(bǔ)補(bǔ)基礎(chǔ)波丰,探究構(gòu)造函數(shù)和new操作究竟是個(gè)什么東西蹬敲。
The new Operator
首先我去翻了翻MDN關(guān)于New操作詳解暇昂,簡(jiǎn)單地摘一些比較關(guān)鍵信息:
When the code new Foo(...) is executed, the following things happen:
- A new object is created, inheriting from Foo.prototype
- The constructor function Foo is called with the specified arguments, and with this bound to the newly created object.
用代碼表示如下:
// 模擬var foo = new Foo('foo')的過程
// A new object is created
var foo = {}
// inheriting from Foo.prototype
foo.__proto__ = Foo.prototype
// The constructor function Foo is called with the specified arguments, and with this bound to the newly created object.
Foo.call(foo, 'foo')
為了更好的理解為什么是foo.__proto__ = Foo.prototype
,我需要對(duì)__proto__
和prototype
之間的關(guān)系的作更深入探究伴嗡。
prototype
-
prototype
是什么急波?- 構(gòu)造函數(shù)的一個(gè)屬性
- 包涵
constructor
字段的一個(gè)Object
- 誰(shuí)有
prototype
?- 所有非原生函數(shù)與原生構(gòu)造函數(shù)
// 原生函數(shù)不能成為構(gòu)造函數(shù)瘪校,沒有prototype屬性
var nativeFunction = Function.prototype.call
console.log(nativeFunction.__proto__) // function () {}
console.log(nativeFunction.prototype) // undefined
new nativeFunction() // Uncaught TypeError: nativeFunction is not a constructor
prototype
是構(gòu)造函數(shù)才具備的屬性澄暮,稱呼其“原型”名段,其實(shí)是相當(dāng)不嚴(yán)謹(jǐn)甚至嚴(yán)重誤導(dǎo)的說法。prototype
本質(zhì)是JavaScript這門語(yǔ)言為開發(fā)人員操作原型對(duì)外暴露的一個(gè)接口泣懊。開發(fā)人員對(duì)prototype
的操作伸辟,最終都會(huì)反映到該改構(gòu)造函數(shù)的實(shí)例的__proto__
上。
熱愛面向?qū)ο蟮呐笥岩欢ê苁煜は旅孢@段代碼馍刮。
var Foo = function () {}
Foo.prototype = {
constructor: Foo,
// ...
}
var foo = new Foo()
我們重寫了Foo.prototype
信夫,都必須手動(dòng)添加constructor
。如果不這樣做的話卡啰,實(shí)例的原型foo.__proto__
將找不到constructor
静稻。
[[proto]]
-
__proto__
是什么?- 原型鏈上的一個(gè)原型
- 誰(shuí)有
__proto__
匈辱?- 所有Object都有(null除外)
var Foo = function () {}
var foo = new Foo()
// 構(gòu)造函數(shù) Foo => function () {} => Object {} => null
console.log(Foo.__proto__) // function () {}
console.log(Foo.__proto__.__proto__) // Object {} | 注意與構(gòu)造函數(shù)Object區(qū)別
console.log(Foo.__proto__.__proto__.__proto__) // null | 是不是很意外振湾?typeof null === Object并非空穴來風(fēng)
// 實(shí)例 foo => { constructor: (...), __proto__: (...) } => Object {} => null
console.log(foo.__proto__) // { constructor, __proto__,... } | 這是由Foo的prototype屬性決定的
console.log(foo.__proto__.__proto__) // Object {}
console.log(foo.__proto__.__proto__.__proto__) // null
總結(jié)
prototype
的意義在于開發(fā)人員可以以此定義實(shí)例的原型,這也是JavaScript
面向?qū)ο蟮幕A(chǔ)梅誓。
__proto__
在原型的維度上自成一列恰梢,構(gòu)建了JavaScript
強(qiáng)大的原型體系,與prototype
不是一個(gè)層次上的概念梗掰。
如果一定要說二者有什么關(guān)系的話嵌言,我覺得應(yīng)該說毫無關(guān)系。
// 這不是代碼
Foo.prototype.constructor => Foo
Foo.prototype.constructor.prototype.constructor => Foo
Foo.prototype.constructor.prototype.constructor.prototype.constructor => Foo
Foo.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor => Foo
// 無窮無盡... 我仿佛看見了循環(huán)鏈表的數(shù)據(jù)結(jié)構(gòu)