1. 什么是 JS 原型鏈?
2. this 的值到底是什么?
3. JS 的 new 到底是干什么的?
這是 JS 里的三個經(jīng)典概念,自學(xué)者必須學(xué)會,否則無法通過面試。
今天主要來說一說自己對JS原型鏈繼承的理解。
我們知道 JS 有對象,比如
var obj = { name: 'obj' }
我們可以對 obj 進行一些操作,包括
- 「讀」屬性
- 「新增」屬性
- 「更新」屬性
- 「刪除」屬性
下面我們主要來看一下「讀」和「新增」屬性。
為什么有 valueOf / toString 屬性呢?
在我們沒有對 obj 進行任何其他操作之前,發(fā)現(xiàn) obj 已經(jīng)有幾個屬性(方法)了:
那么問題來了:valueOf / toString / constructor 是怎么來?我們并沒有給 obj.valueOf 賦值呀。
要搞清楚 valueOf / toString / constructor 是怎么來的,就要用到 console.dir 了。
我們發(fā)現(xiàn) console.dir(obj) 打出來的結(jié)果是:
- obj 本身有一個屬性 name(這是我們給它加的)
- obj 還有一個屬性叫做 proto(它是一個對象)
- obj.proto 有很多屬性,包括 valueOf、toString、constructor 等
- obj.proto 其實也有一個叫做 proto 的屬性(console.log 沒有顯示),值為 null
現(xiàn)在回到我們的問題:obj 為什么會擁有 valueOf / toString / constructor 這幾個屬性?
答案:
這跟 proto 有關(guān)。
當(dāng)我們「讀取」 obj.toString 時,JS 引擎會做下面的事情:
- 看看 obj 對象本身有沒有 toString 屬性。沒有就走到下一步。
- 看看 obj.proto 對象有沒有 toString 屬性,發(fā)現(xiàn) obj.proto 有 toString 屬性,于是找到了
所以 obj.toString 實際上就是第 2 步中找到的 obj.proto.toString。
可以想象, - 如果 obj.proto 沒有,那么瀏覽器會繼續(xù)查看 obj.proto.proto
- 如果 obj.proto.proto 也沒有,那么瀏覽器會繼續(xù)查看 obj.proto.proto.proto__
- 直到找到 toString 或者 proto 為 null。
上面的過程,就是「讀」屬性的「搜索過程」。
而這個「搜索過程」,是連著由 proto 組成的鏈子一直走的。
這個鏈子,就叫做「原型鏈」。
共享原型鏈
現(xiàn)在我們有另一個對象
var obj2 = { name: 'obj2' }
如圖:
那么 obj.toString 和 obj2.toString 其實是同一個東西,也就是 obj2.proto.toString。
這有什么意義呢?
如果我們改寫 obj2.proto.toString,那么 obj.toString 其實也會變!
這樣 obj 和 obj2 就是具有某些相同行為的對象,這就是意義所在。
差異化
如果我們想讓 obj.toString 和 obj2.toString 的行為不同怎么做呢?
直接賦值就好了:
obj.toString = function(){ return '新的 toString 方法' }
總結(jié):
「讀」屬性時會沿著原型鏈搜索。
「新增」屬性時不會去看原型鏈(但是如果你給這個屬性加了一些配置,則不一樣,以后講)。