javascript進階-《原型對象和原型鏈》

 原創發佈 by @一像素 2015.12javascript

 在Javascript中,萬物皆對象,但對象也有區別,大體能夠分爲兩類,即:普通對象Object 和 函數對象Functionhtml

   通常而言,經過new Function產生的對象是函數對象,其餘對象都是普通對象。java

 1 function f1(){
 2     //todo
 3 }
 4 var f2 = function(){
 5     //todo
 6 };
 7 var f3 = new Function('x','console.log(x)');
 8  
 9 var o1 = {};
10 var o2 = new Object();
11 var o3 = new f1();
12  
13 console.log(
14     typeof f1,//function
15     typeof f2,//function
16     typeof f3,//function
17     typeof o1,//object
18     typeof o2,//object
19     typeof o3 //object
20 );

f1屬於函數的聲明,最多見的函數定義方式,f2其實是一個匿名函數,把這個匿名函數賦值給了f2,屬於函數表達式,f3不常見,但也是一種函數對象。函數

Function是JS自帶的對象,f1,f2在建立的時候,JS會自動經過new Function()的方式來構建這些對象,所以,這三個對象都是經過new Function()建立的。spa

在Javascript中建立對象有兩種方式:對象字面量和使用new表達式,o1和o2的建立剛好對應了這兩種方式,重點講一下o3, 若是用Java和C#的思路來理解的話,o3是f1的實例對象,o3和f1是同一類型,至少我之前這麼認爲,其實否則...prototype

那麼怎麼理解呢? 很簡單,看o3是否是經過new Function產生的, 顯然不是,既然不是函數對象,那就是普通對象 。code

經過對函數對象和普通對象的簡單理解以後,咱們再來了解一下Javascript中的原型和原型鏈:htm

在JS中,每當建立一個函數對象f1 時,該對象中都會內置一些屬性,其中包括prototype和__proto__,  prototype即原型對象,它記錄着f1的一些屬性和方法。對象

須要注意的是,prototype 對f1是不可見的,也就是說,f1不會查找prototype中的屬性和方法。 blog

1 function f(){}
2 f.prototype.foo = "abc";
3 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就會在原型鏈上找到這個屬性並執行。 

最後,用幾句話總結一下本文中涉及到的重點:

  • 原型鏈的造成真正是靠__proto__ 而非prototype,當JS引擎執行對象的方法時,先查找對象自己是否存在該方法,若是不存在,會在原型鏈上查找,但不會查找自身的prototype。
  • 一個對象的__proto__記錄着本身的原型鏈,決定了自身的數據類型,改變__proto__就等於改變對象的數據類型。
  • 函數的prototype不屬於自身的原型鏈,它是子類建立的核心,決定了子類的數據類型,是鏈接子類原型鏈的橋樑。
  • 在原型對象上定義方法和屬性的目的是爲了被子類繼承和使用。
相關文章
相關標籤/搜索