原型對(duì)象和原型鏈

對(duì)象大致可以分為兩類,即:普通對(duì)象 Object 和 函數(shù)對(duì)象 Function。

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,//function
    typeof f2,//function
    typeof f3,//function
    typeof o1,//object
    typeof o2,//object
    typeof o3 //object
);

f1屬于函數(shù)的聲明,最常見的函數(shù)定義方式,f2實(shí)際上是一個(gè)匿名函數(shù),把這個(gè)匿名函數(shù)賦值給了f2,屬于函數(shù)表達(dá)式,f3不常見,但也是一種函數(shù)對(duì)象。

Function是JS自帶的對(duì)象,f1,f2在創(chuàng)建的時(shí)候,JS會(huì)自動(dòng)通過new Function()的方式來構(gòu)建這些對(duì)象,因此,這三個(gè)對(duì)象都是通過new Function()創(chuàng)建的。

在Javascript中創(chuàng)建對(duì)象有兩種方式:對(duì)象字面量和使用new表達(dá)式,o1和o2的創(chuàng)建恰好對(duì)應(yīng)了這兩種方式,重點(diǎn)講一下o3, 如果用Java和C#的思路來理解的話,o3是f1的實(shí)例對(duì)象,o3和f1是同一類型,至少我以前這么認(rèn)為,其實(shí)不然...
怎么理解呢? 很簡單,看 o3 是不是通過 new Function 產(chǎn)生的,顯然不是,既然不是函數(shù)對(duì)象,那就是普通對(duì)象 。

通過對(duì)函數(shù)對(duì)象和普通對(duì)象的簡單理解之后,我們?cè)賮砹私庖幌翵avascript中的原型和原型鏈:

在JS中,每當(dāng)創(chuàng)建一個(gè)函數(shù)對(duì)象 f1 時(shí),該對(duì)象中都會(huì)內(nèi)置一些屬性,其中包括 prototype 和 proto, prototype 即原型對(duì)象,它記錄著f1的一些屬性和方法。

需要注意的是,prototype 對(duì) f1 是不可見的,也就是說,f1 不會(huì)查找 prototype 中的屬性和方法。

function f(){}
f.prototype.foo = "abc";
console.log(f.foo); //undefined

那么,prototype 有什么用呢? 其實(shí) prototype 的主要作用就是繼承。 通俗一點(diǎn)講,prototype 中定義的屬性和方法都是留給自己的 “后代” 用的,因此,子類完全可以訪問prototype中的屬性和方法。

想要知道 f1 是如何把 prototype 留給“后代”,我們需要了解一下 JS 中的原型鏈。此時(shí),JS中的 proto 入場了,這哥們長的很奇特,隱藏的也很深,以致于你經(jīng)常見不到它,但它在普通對(duì)象和函數(shù)對(duì)象中都存在, 它的作用就是引用父類的 prototype 對(duì)象,JS在通過 new 操作符創(chuàng)建一個(gè)對(duì)象的時(shí)候,通常會(huì)把父類的 prototype 賦值給新對(duì)象的proto屬性,這樣就形成了一代代傳承...

function f(){}
f.prototype.foo = "abc";
var obj = new f();
console.log(obj.foo); //abc

image.png

如圖所示,f.prototype 的 proto 中保存的是 Object.prototype,Object.prototype 對(duì)象中也有 proto,而從輸出結(jié)果看,Object.prototype.proto 是 null,表示 obj 對(duì)象原型鏈的終結(jié)。如下圖所示:

image.png

obj 對(duì)象擁有這樣一個(gè)原型鏈以后,當(dāng) obj.foo 執(zhí)行時(shí),obj 會(huì)先查找自身是否有該屬性,但不會(huì)查找自己的 prototype,當(dāng)找不到foo時(shí),obj 就沿著原型鏈依次去查找...

在上面的例子中,我們?cè)趂的prototype上定義了 foo 屬性,這時(shí) obj 就會(huì)在原型鏈上找到這個(gè)屬性并執(zhí)行。

最后,總結(jié)一下本文中涉及到的重點(diǎn):

  • 原型鏈的形成真正是靠proto 而非prototype,當(dāng)JS引擎執(zhí)行對(duì)象的方法時(shí),先查找對(duì)象本身是否存在該方法,如果不存在,會(huì)在原型鏈上查找,但不會(huì)查找自身的prototype。
  • 一個(gè)對(duì)象的 proto 記錄著自己的原型鏈,決定了自身的數(shù)據(jù)類型,改變 proto 就等于改變對(duì)象的數(shù)據(jù)類型。
  • 函數(shù)的 prototype 不屬于自身的原型鏈,它是創(chuàng)建子類的核心,決定了子類的數(shù)據(jù)類型,是連接子類原型鏈的橋梁。
  • 在原型對(duì)象上定義方法和屬性,是為了被子類繼承和使用。

參考: 一像素

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容