我為什么要把 javascript.prototype
原型單獨(dú)拿出一系列博客來(lái)寫(xiě)?
因?yàn)槠綍r(shí)寫(xiě)js代碼的時(shí)候很少用到!!!惊窖!
我為什么平時(shí)寫(xiě)js代碼的時(shí)候很少用到?
因?yàn)槠綍r(shí)我寫(xiě)js代碼,特別是對(duì)象的時(shí)候.不出意外,99.99999%的情況都是使用字面量的寫(xiě)法!@逶簟=缇啤!
var obj = {
.....
}
一個(gè)簡(jiǎn)單的場(chǎng)景
我們使用字面量(99.9999%的情況都是如此)聲明一個(gè)對(duì)象.
var obj = {
name: '李四',
age: 22
}
然后調(diào)用
obj.showInfo()
不出意外,肯定報(bào)錯(cuò).且報(bào)錯(cuò)信息是 obj.showInfo is not function
..
到目前為止,從來(lái)都沒(méi)有人懷疑過(guò).
這里就應(yīng)該報(bào)錯(cuò).因?yàn)槟銢](méi)有定義這個(gè)方法.
那如果我調(diào)用obj.toString()方法呢?
[object Object]
我沒(méi)有定義 toString
方法,為什么不報(bào)錯(cuò),還正確執(zhí)行了呢?
這個(gè) toString
的方法是哪里來(lái)的?
Object.prototype
在解釋 toString
方法哪里來(lái)的之前
有一個(gè)規(guī)則需要知道: (什么是規(guī)則?規(guī)則就是你可以先不去理解,但是必須強(qiáng)行記憶和知道的知識(shí))
在js中函數(shù)也是對(duì)象,所有的函數(shù)對(duì)象上會(huì)有一個(gè)
.prototype
的屬性.
Object 也是一個(gè)函數(shù),所以,它也有 .prototype
屬性.===> Object.prototype
打印一下 Object.prototype
這個(gè)對(duì)象上有哪些屬性?
(請(qǐng)注意,在瀏覽器環(huán)境中打印,在Node.js環(huán)境中打印將會(huì)返回一個(gè)空對(duì)象)
所以,我們可以先暫時(shí)假定: obj.toString
方法是來(lái)自 Object.prototype
對(duì)象上的.
代碼改造
之前我們的代碼是
var obj = {
name: '李四',
age: 22
}
console.log(obj.toString())
[object Object]
之前也說(shuō)過(guò),一般在書(shū)寫(xiě)js代碼創(chuàng)建一個(gè)對(duì)象時(shí).
不夸張的說(shuō) 99.9999999% 的情況都是寫(xiě)的對(duì)象字面量(就像上述那樣)
但實(shí)際上,這段代碼也可以改寫(xiě)成這樣.
var obj = new Object()
obj.name = '李四'
obj.age = 22
我們可以理解成,對(duì)象字面量其實(shí)是一個(gè)語(yǔ)法糖.
它幫我們隱式的調(diào)用了 new Object()
.
所以,在我們寫(xiě)js代碼利用對(duì)象字面量創(chuàng)建對(duì)象的時(shí)候,new Object() 其實(shí)無(wú)處不在(因?yàn)?9.9999%的情況下,我們都是使用對(duì)象字面量來(lái)創(chuàng)建對(duì)象.反而忽略了new的存在.).
new Object()
現(xiàn)在我們知道了,使用對(duì)象字面量創(chuàng)建對(duì)象只是一個(gè)語(yǔ)法糖.
其內(nèi)部幫我們調(diào)用了 new Object()
.
如果要了解為什么 obj.toString()
沒(méi)問(wèn)題.
還需要知道一個(gè)前置規(guī)則(第一個(gè)是:所有的函數(shù)都包含一個(gè).prototype屬性)
所有構(gòu)造的對(duì)象(隱式或顯式(用new).都會(huì)從它的構(gòu)造函數(shù)對(duì)象的prototype對(duì)象繼承.
于是,可以畫(huà)一下面這張圖.
-
Object
是一個(gè)函數(shù),它有一個(gè)屬性叫.prototype
. -
.prototype
屬性本身也是一個(gè)對(duì)象,它也右邊那些屬性和方法. -
obj
實(shí)際上是Object
函數(shù)構(gòu)造出出來(lái)的實(shí)例.所以,根據(jù)第二條規(guī)則,通過(guò)new Object()
創(chuàng)建出來(lái)的對(duì)象,都會(huì)從Object.prototype
對(duì)象上繼承屬性和方法. - 所以,我們調(diào)用
obj.toString
實(shí)際上是調(diào)用的Object.protoype.toString
方法.
證明obj.toString === Object.prototype.toString
我們先嘗試修改一下 Object.prototype.toString
讓它專(zhuān)門(mén)為 obj
對(duì)象來(lái)使用.
Object.prototype.toString = function () {
console.log(this.name, this.age)
}
obj.toString()
李四 22
關(guān)于 prototype 對(duì)象屬性的COW(copy on write)
現(xiàn)在在創(chuàng)建一個(gè)對(duì)象字面量,但內(nèi)部沒(méi)有 name
和 age
屬性.
const obj2 = {}
根據(jù)上述的規(guī)則一 & 規(guī)則二.所以下列這條等式是成立的.
console.log(obj2.toString === Object.prototype.toString) // true.
如果我現(xiàn)利用 obj2
修改了 toString
函數(shù),會(huì)對(duì) obj
產(chǎn)生影響嗎?
obj2.toString = function() {
console.log('toString函數(shù)被我重寫(xiě)了.')
}
obj.toString()
結(jié)果
李四 22
除非修改 prototype 對(duì)象本身,否則繼承自這個(gè) prototype 對(duì)象的對(duì)象,做的任何修改只會(huì)影響此對(duì)象自己.
而不會(huì)影響到其他的對(duì)象.
這個(gè)就叫做原型對(duì)象的 COW ==copy on write 寫(xiě)時(shí)復(fù)刻==