摘要:一大家都知道一般就是用來檢查對象是否為類或子類的實例。中兩者均指向,因此添加到的屬性,也會出現在的中。四其實是建議實現者如采用的底層優化手段。因為中定義函數啥都一樣,所以底層實現可以不再生成一個新的,從而從空間和時間上降低消耗。
一、Breif
大家都知道instanceof一般就是用來檢查A對象是否為B類或子類的實例。那問題是JS中沒有類的概念更沒有類繼承的概念(雖然有構造函數),那么instanceof到底是怎樣判斷A對象是B構造函數的實例呢?本文將對此作分析記錄,以便日后查閱。
二、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).
從上述的定義我們可以得出以下內容:
ShiftExpression的實際值(GetValue(Evaluate(ShiftExpression)))必須為[object Function],否則就拋TypeError異常;
instanceof的實際判斷則是調用RelationalExpression的Internal Method [[HasInstance]]來處理。
下面我們深入一下[[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的實現吧
// IE5.5~9下,由于無法通過__proto__訪問對象的Internal Property [[Prototype]],因此該方法無效 ;(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)*/))
現在稍微總結一下,a instanceof b底層的運算機制關鍵點如下:
b的數據類型必須為[object Function],否則就拋TypeError;
若a為Primitive Value則直接返回false, 若a的數據類型為Object則執行后續運算;
當且僅當b.prototype位于a的prototype chain中時,才返回true(由于Object.prototype.__proto__為null,因此prototype chain是有限鏈表);
也許大家會對 Function.prototype["[[HasInstance]]"] 的實現為什么能成功感到疑問,我們先看看以下圖片
可以知道所有函數的 proto 默認情況下均指向 Function.prototype ,而 Function.__proto__ 則與 Function.prototype 指向同一個對象。
Chrome中兩者均指向function Empty(){},因此添加到Function.protoype的屬性,也會出現在Function的prototype chain中。
四、About if they refer to objects joined to each otherObjects Joined其實是Spec建議實現者(如V8、SpiderMonkey)采用的底層優化手段。
function a(){ function b(){} return b } var c = a() var d = a() // 假如JavaScript Engine實現了Objects Joined,那么 c === d 返回值為true。因為a中定義b函數啥都一樣,所以底層實現可以不再生成一個新的Function object,從而從空間和時間上降低消耗。五 、Conclusion
之前看了很多講述instanceof的文章但始終對它理解得不透徹,看來還是看Spec比較實在。
六、Thankshttp://www.w3cfuns.com/article-5597466-1-1.html
http://dmitrysoshnikov.com/ecmascript/chapter-5-functions/
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85848.html
摘要:五的子類對象會返回一個集合對象,集合內存儲類型的元素。七的子類初看很有可能以為集合元素就是單選表單元素,其實可以存儲任意類型的表單元素。八的子類開始,將返回子類的對象,其行為特征和一致。但在前,我們應該先了解清楚的類型的特征。 一、前言 大家先看看下面的js,猜猜結果會怎樣吧! 可選答案: ①. 獲取id屬性值為id的節點元素 ②...
摘要:我打算分成前端魔法堂異常不僅僅是和前端魔法堂調用棧,異常實例中的寶藏兩篇分別敘述內置自定義異常類,捕獲運行時異常語法異常網絡請求異常事件,什么是調用棧和如何獲取調用棧的相關信息。 前言 ?編程時我們往往拿到的是業務流程正確的業務說明文檔或規范,但實際開發中卻布滿荊棘和例外情況,而這些例外中包含業務用例的例外,也包含技術上的例外。對于業務用例的例外我們別無它法,必須要求實施人員與用戶共同...
摘要:坑無視和是十分特殊的事件,要求事件處理函數內部不能阻塞當前線程,而卻恰恰就會阻塞當前線程,因此規范中以明確在和中直接無視這幾個方法的調用。 前言 ?最近實施的同事報障,說用戶審批流程后直接關閉瀏覽器,操作十余次后系統就報用戶會話數超過上限,咨詢4A同事后得知登陸后需要顯式調用登出API才能清理4A端,否則必然會超出會話上限。?即使在頁面上增添一個登出按鈕也無法保證用戶不會直接關掉瀏覽器...
摘要:也就是說我們操作的幾何公式中的未知變量,而具體的畫圖操作則由渲染引擎處理,而不是我們苦苦哀求設計師幫忙。 前言 ?當CSS3推出border-radius屬性時我們是那么欣喜若狂啊,一想到終于不用再添加額外元素來模擬圓角了,但發現border-radius還分水平半徑和垂直半徑,然后又發現border-top-left/right-radius的水平半徑之和大于元素寬度時,實際值會按比...
摘要:本系列將稍微深入探討一下那個貌似沒什么好玩的魔法堂重拾之解構魔法堂重拾之圖片作邊框魔法堂重拾之不僅僅是圓角魔法堂重拾之更廣闊的遐想解構說起我們自然會想起,而由條緊緊包裹著的邊組成,所以的最小操作單元是。 前言 ?當CSS3推出border-radius屬性時我們是那么欣喜若狂啊,一想到終于不用再添加額外元素來模擬圓角了,但發現border-radius還分水平半徑和垂直半徑,然后又發現...
閱讀 3456·2023-04-26 00:39
閱讀 4059·2021-09-22 10:02
閱讀 2543·2021-08-09 13:46
閱讀 1102·2019-08-29 18:40
閱讀 1447·2019-08-29 18:33
閱讀 775·2019-08-29 17:14
閱讀 1517·2019-08-29 12:40
閱讀 2979·2019-08-28 18:07