摘要:一大家都知道一般就是用來(lái)檢查對(duì)象是否為類(lèi)或子類(lèi)的實(shí)例。中兩者均指向,因此添加到的屬性,也會(huì)出現(xiàn)在的中。四其實(shí)是建議實(shí)現(xiàn)者如采用的底層優(yōu)化手段。因?yàn)橹卸x函數(shù)啥都一樣,所以底層實(shí)現(xiàn)可以不再生成一個(gè)新的,從而從空間和時(shí)間上降低消耗。
一、Breif
大家都知道instanceof一般就是用來(lái)檢查A對(duì)象是否為B類(lèi)或子類(lèi)的實(shí)例。那問(wèn)題是JS中沒(méi)有類(lèi)的概念更沒(méi)有類(lèi)繼承的概念(雖然有構(gòu)造函數(shù)),那么instanceof到底是怎樣判斷A對(duì)象是B構(gòu)造函數(shù)的實(shí)例呢?本文將對(duì)此作分析記錄,以便日后查閱。
二、Reference 2 ECMA-262-3 Spechttp://bclary.com/2004/11/07/#a-11.8.6
The production RelationalExpression: RelationalExpression instanceof ShiftExpression is evaluated as follows:
Evaluate RelationalExpression.
Call GetValue(Result(1)).
Evaluate ShiftExpression.
Call GetValue(Result(3)).
If Result(4) is not an object, throw a TypeError exception.
If Result(4) does not have a [[HasInstance]] method, throw a TypeError exception.
Call the [[HasInstance]] method of Result(4) with parameter Result(2).
Return Result(7).
從上述的定義我們可以得出以下內(nèi)容:
ShiftExpression的實(shí)際值(GetValue(Evaluate(ShiftExpression)))必須為[object Function],否則就拋TypeError異常;
instanceof的實(shí)際判斷則是調(diào)用RelationalExpression的Internal Method [[HasInstance]]來(lái)處理。
下面我們深入一下[[HasInstance]]的定義
http://bclary.com/2004/11/07/#a-15.3.5.3
> Assume F is a Function object.
> When the [[HasInstance]] method of F is called with value V, the following steps are taken:
> 1. If V is not an object, return false.
> 2. Call the [[Get]] method of F with property name "prototype".
> 3. Let O be Result(2).
> 4. If O is not an object, throw a TypeError exception.
> 5. Let V be the value of the [[Prototype]] property of V.
> 6. If V is null, return false.
> 7. If O and V refer to the same object or if they refer to objects joined to each other (13.1.2), return true.
> 8. Go to step 5.
上面的定義看得不太明白,我們把它翻譯成JS的實(shí)現(xiàn)吧
// IE5.5~9下,由于無(wú)法通過(guò)__proto__訪(fǎng)問(wèn)對(duì)象的Internal Property [[Prototype]],因此該方法無(wú)效 ;(function(rNotObj){ Function.prototype["[[HasInstance]]"] = function(value){ // 1. If V is not an object, return false if (rNotObj.test(typeof value)) return false // 2. Call the [[Get]] method of F with property name "prototype" // 4. If O is not an object, throw a TypeError exception var O = this.prototype if (rNotObj.test(typeof O)) throw TypeError() // 5. Let V be the value of the [[Prototype]] prototype of V // 6. If V is null, return false if (null === (value = value.__proto__)) return false // 7. If O and V refer to the same object // 8. Go to step 5 return O === value || this["[[HasInstance]]"](value) } }(/$[^of]/ /*not begin with o(bject) neither f(unction)*/))
現(xiàn)在稍微總結(jié)一下,a instanceof b底層的運(yùn)算機(jī)制關(guān)鍵點(diǎn)如下:
b的數(shù)據(jù)類(lèi)型必須為[object Function],否則就拋TypeError;
若a為Primitive Value則直接返回false, 若a的數(shù)據(jù)類(lèi)型為Object則執(zhí)行后續(xù)運(yùn)算;
當(dāng)且僅當(dāng)b.prototype位于a的prototype chain中時(shí),才返回true(由于Object.prototype.__proto__為null,因此prototype chain是有限鏈表);
也許大家會(huì)對(duì) Function.prototype["[[HasInstance]]"] 的實(shí)現(xiàn)為什么能成功感到疑問(wèn),我們先看看以下圖片
可以知道所有函數(shù)的 proto 默認(rèn)情況下均指向 Function.prototype ,而 Function.__proto__ 則與 Function.prototype 指向同一個(gè)對(duì)象。
Chrome中兩者均指向function Empty(){},因此添加到Function.protoype的屬性,也會(huì)出現(xiàn)在Function的prototype chain中。
四、About if they refer to objects joined to each otherObjects Joined其實(shí)是Spec建議實(shí)現(xiàn)者(如V8、SpiderMonkey)采用的底層優(yōu)化手段。
function a(){ function b(){} return b } var c = a() var d = a() // 假如JavaScript Engine實(shí)現(xiàn)了Objects Joined,那么 c === d 返回值為true。因?yàn)閍中定義b函數(shù)啥都一樣,所以底層實(shí)現(xiàn)可以不再生成一個(gè)新的Function object,從而從空間和時(shí)間上降低消耗。五 、Conclusion
之前看了很多講述instanceof的文章但始終對(duì)它理解得不透徹,看來(lái)還是看Spec比較實(shí)在。
六、Thankshttp://www.w3cfuns.com/article-5597466-1-1.html
http://dmitrysoshnikov.com/ecmascript/chapter-5-functions/
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/85848.html
摘要:五的子類(lèi)對(duì)象會(huì)返回一個(gè)集合對(duì)象,集合內(nèi)存儲(chǔ)類(lèi)型的元素。七的子類(lèi)初看很有可能以為集合元素就是單選表單元素,其實(shí)可以存儲(chǔ)任意類(lèi)型的表單元素。八的子類(lèi)開(kāi)始,將返回子類(lèi)的對(duì)象,其行為特征和一致。但在前,我們應(yīng)該先了解清楚的類(lèi)型的特征。 一、前言 大家先看看下面的js,猜猜結(jié)果會(huì)怎樣吧! 可選答案: ①. 獲取id屬性值為id的節(jié)點(diǎn)元素 ②...
摘要:我打算分成前端魔法堂異常不僅僅是和前端魔法堂調(diào)用棧,異常實(shí)例中的寶藏兩篇分別敘述內(nèi)置自定義異常類(lèi),捕獲運(yùn)行時(shí)異常語(yǔ)法異常網(wǎng)絡(luò)請(qǐng)求異常事件,什么是調(diào)用棧和如何獲取調(diào)用棧的相關(guān)信息。 前言 ?編程時(shí)我們往往拿到的是業(yè)務(wù)流程正確的業(yè)務(wù)說(shuō)明文檔或規(guī)范,但實(shí)際開(kāi)發(fā)中卻布滿(mǎn)荊棘和例外情況,而這些例外中包含業(yè)務(wù)用例的例外,也包含技術(shù)上的例外。對(duì)于業(yè)務(wù)用例的例外我們別無(wú)它法,必須要求實(shí)施人員與用戶(hù)共同...
摘要:坑無(wú)視和是十分特殊的事件,要求事件處理函數(shù)內(nèi)部不能阻塞當(dāng)前線(xiàn)程,而卻恰恰就會(huì)阻塞當(dāng)前線(xiàn)程,因此規(guī)范中以明確在和中直接無(wú)視這幾個(gè)方法的調(diào)用。 前言 ?最近實(shí)施的同事報(bào)障,說(shuō)用戶(hù)審批流程后直接關(guān)閉瀏覽器,操作十余次后系統(tǒng)就報(bào)用戶(hù)會(huì)話(huà)數(shù)超過(guò)上限,咨詢(xún)4A同事后得知登陸后需要顯式調(diào)用登出API才能清理4A端,否則必然會(huì)超出會(huì)話(huà)上限。?即使在頁(yè)面上增添一個(gè)登出按鈕也無(wú)法保證用戶(hù)不會(huì)直接關(guān)掉瀏覽器...
摘要:也就是說(shuō)我們操作的幾何公式中的未知變量,而具體的畫(huà)圖操作則由渲染引擎處理,而不是我們苦苦哀求設(shè)計(jì)師幫忙。 前言 ?當(dāng)CSS3推出border-radius屬性時(shí)我們是那么欣喜若狂啊,一想到終于不用再添加額外元素來(lái)模擬圓角了,但發(fā)現(xiàn)border-radius還分水平半徑和垂直半徑,然后又發(fā)現(xiàn)border-top-left/right-radius的水平半徑之和大于元素寬度時(shí),實(shí)際值會(huì)按比...
摘要:本系列將稍微深入探討一下那個(gè)貌似沒(méi)什么好玩的魔法堂重拾之解構(gòu)魔法堂重拾之圖片作邊框魔法堂重拾之不僅僅是圓角魔法堂重拾之更廣闊的遐想解構(gòu)說(shuō)起我們自然會(huì)想起,而由條緊緊包裹著的邊組成,所以的最小操作單元是。 前言 ?當(dāng)CSS3推出border-radius屬性時(shí)我們是那么欣喜若狂啊,一想到終于不用再添加額外元素來(lái)模擬圓角了,但發(fā)現(xiàn)border-radius還分水平半徑和垂直半徑,然后又發(fā)現(xiàn)...
閱讀 3468·2023-04-26 00:39
閱讀 4077·2021-09-22 10:02
閱讀 2561·2021-08-09 13:46
閱讀 1108·2019-08-29 18:40
閱讀 1457·2019-08-29 18:33
閱讀 784·2019-08-29 17:14
閱讀 1525·2019-08-29 12:40
閱讀 2985·2019-08-28 18:07