在Javascript中,萬物皆對象,但對象也有區別,大體能夠分爲兩類,即:普通對象 Object 和 函數對象 Function。html
通常而言,經過 new Function 產生的對象是函數對象,其餘對象都是普通對象。函數
舉例說明:prototype
function f1() { // todo } var f2 = function () { // todo }; var f3 = new Function('x', 'console.log(x)'); var o1 = {}; var o2 = new Object(); var o3 = new f1(); console.log( typeof f1, typeof f2, typeof f3, typeof o1, typeof o2, typeof o3 ); > function function function object object object
f1屬於函數的聲明,最多見的函數定義方式,f2其實是一個匿名函數,把這個匿名函數賦值給了f2,屬於函數表達式,f3不常見,但也是一種函數對象。htm
Function 是JS自帶的對象,f1,f2 在建立的時候,JS會自動經過 new Function() 的方式來構建這些對象,所以,這三個對象都是經過 new Function() 建立的。對象
在 Javascript 中建立對象有兩種方式:對象字面量和使用new表達式,o1和o2的建立剛好對應了這兩種方式,重點講一下o3, 若是用Java和C#的思路來理解的話,o3是f1的實例對象,o3和f1是同一類型,至少我之前這麼認爲,其實否則...blog
怎麼理解呢? 很簡單,看 o3 是否是經過 new Function 產生的,顯然不是,既然不是函數對象,那就是普通對象 。繼承
經過對函數對象和普通對象的簡單理解以後,咱們再來了解一下 Javascript 中的原型和原型鏈:ip
在 JS 中,每當建立一個函數對象 f1 時,該對象中都會內置一些屬性,其中包括 prototype 和 __proto__, prototype 即原型對象,它記錄着f1的一些屬性和方法。原型鏈
須要注意的是,prototype 對 f1 是不可見的,也就是說,f1 不會查找 prototype 中的屬性和方法。 get
function f(){} f.prototype.foo = "abc"; console.log(f.foo); // undefined
那麼,prototype 有什麼用呢? 其實 prototype 的主要做用就是繼承。 通俗一點講,prototype 中定義的屬性和方法都是留給本身的 「後代」 用的,所以,子類徹底能夠訪問prototype中的屬性和方法。
想要知道 f1 是如何把 prototype 留給「後代」,咱們須要瞭解一下 JS 中的原型鏈。此時,JS中的 __proto__ 入場了,它存在於普通對象和函數對象中,它的做用就是引用父類的 prototype 對象,JS在經過 new 操做符建立一個對象的時候,一般會把父類的 prototype 賦值給新對象的 __proto__屬性,這樣就造成了一代代傳承...
function f() {} f.prototype.foo = "abc"; var obj = new f(); console.log(obj.foo); // abc
如今咱們知道,obj中__proto__保存的是 f 的 prototype,那麼 f 的 prototype 中的 __proto__ 中保存的是什麼呢? 看下圖:
如圖所示,f.prototype 的 __proto__ 中保存的是 Object.prototype,Object.prototype 對象中也有 __proto__,而從輸出結果看,Object.prototype.__proto__ 是 null,表示 obj 對象原型鏈的終結。以下圖所示:
obj 對象擁有這樣一個原型鏈之後,當 obj.foo 執行時,obj 會先查找自身是否有該屬性,但不會查找本身的 prototype,當找不到foo時,obj 就沿着原型鏈依次去查找...
在上面的例子中,咱們在f的 prototype 上定義了 foo 屬性,這時 obj 就會在原型鏈上找到這個屬性並執行。
最後,總結一下本文中涉及到的重點:
原創發佈 @一像素 2015.12