我們知道JavaScript中的一個(gè)函數(shù)疾棵,當(dāng)與new一起使用來創(chuàng)建一個(gè)對(duì)象時(shí),就成為了一個(gè)類型痹仙,所創(chuàng)建的對(duì)象叫作這個(gè)類型的實(shí)例(instance)是尔。
以Array來作為例子,Array本身是一個(gè)函數(shù)开仰,當(dāng)創(chuàng)建多個(gè)實(shí)例array1拟枚、array2、array3... ... 這些實(shí)例都擁有push众弓、pop恩溅、slice等方法,并且每一個(gè)array*實(shí)例的這些方法指向的都是同一個(gè)函數(shù)谓娃。
通過下面的例子來證明一下:
var array1 = new Array()
var array2 = new Array()
var res = Object.is(array1.slice, array2.slice) // 比較兩對(duì)象slice方法
console.log(res) // 輸出比較結(jié)果
Object.is(obj1, obj2) 可以用來比較兩個(gè)非數(shù)字脚乡、非字符串對(duì)象是否是同一個(gè)對(duì)象。
上述代碼創(chuàng)建了兩個(gè)Array實(shí)例滨达,然后將兩個(gè)實(shí)例的slice方法進(jìn)行比較奶稠。來看一下運(yùn)行結(jié)果:
true
運(yùn)行結(jié)果為true,說明兩個(gè)實(shí)例的slice方法引用的是同一個(gè)函數(shù)弦悉。為什么兩個(gè)不同實(shí)例的方法會(huì)指向背后同一個(gè)對(duì)象窒典?這背后的原理是什么蟆炊?
類對(duì)象
每一個(gè)實(shí)例都有一個(gè)__proto__屬性稽莉,對(duì)同一種類型的實(shí)例來說,他位的__proto__屬性指向同一個(gè)對(duì)象涩搓,這個(gè)對(duì)象叫類對(duì)象(class object)污秆。
instance.__proto__ => class object //__proto__指向類對(duì)象
為什么要有類對(duì)象劈猪?我們知道,同一種類型的實(shí)例良拼,既有各自不同的屬性战得,也有各自相同的屬性。各自不同的屬性庸推,存放在各個(gè)實(shí)例內(nèi)部常侦;而相同的屬性,則提取出來贬媒,存在在類對(duì)象中聋亡。
更具體一點(diǎn)的說就是,成員屬性都存儲(chǔ)在實(shí)例中际乘,成員方法都存在在類對(duì)象中坡倔。比如,對(duì)于Array的slice方法來說脖含,slice方法就存儲(chǔ)在Array的類對(duì)象中罪塔。
有使用實(shí)例調(diào)用公共方法時(shí),例如:
array1.slice()
JavaScript引擎會(huì)首先在array1實(shí)際本身尋找slice屬性养葵,因?yàn)閍rray1沒有slice屬性征堪,引擎會(huì)繼續(xù)在array1.proto的類對(duì)象中尋找,對(duì)于Array的slice方法來說关拒,在array1.proto中就能找到请契。
我們把這種根據(jù)proto尋找屬性的流程歸納如下:
- 在實(shí)例中尋找屬性property,如找到則返回該值夏醉,否則繼續(xù)2
- 在實(shí)例proto指向的類對(duì)象中尋找爽锥,找到則返回該值,否則則退出返回空
引用類對(duì)象
上說解釋了什么是類對(duì)象畔柔,那該如何引用類對(duì)象呢氯夷?
對(duì)于自定義類型來說,F(xiàn)unction.prototype指向的就是類對(duì)象靶擦,如:
function Point()
{
}
Point.prototype // 這就是類對(duì)象
另外通過實(shí)例的proto方法也能引用腮考,如:
array1.__proto__ // 這就是類對(duì)象
函數(shù)中是prototype,而實(shí)例中是proto玄捕,注意區(qū)分踩蔚。
另外,JavaScript標(biāo)準(zhǔn)推薦使用Object.getPrototypeOf()來獲取實(shí)例的類對(duì)象枚粘。如:
Object.getPrototypeOf(array1) // 獲取類對(duì)象
OK馅闽,結(jié)束。
什么是繼承?什么是繼承鏈福也?