【译】Typeof null 的历史
Update 2013-11-05:為了更好的解釋為什么 'typeof null' 的結(jié)果是 'object',我查閱了實現(xiàn)的 C 源碼。
在 JavaScript 中,typeof null 的結(jié)果是 object,該結(jié)果錯誤地暗示了 null 是一個對象(null 并不是一個對象,而是一個基本數(shù)據(jù)類型(的值),詳情可以查閱我的博文 categorizing values)。這其實是一個 bug,但更糟的是這個 bug 是不能修復(fù)的,因為修復(fù)這個 bug 會使已經(jīng)存在的程序崩潰。下面就讓我們探索一下這個 bug 的歷史。
typeof null 這個 bug 是 JavaScript 第一個版本遺留下來的。在這個版本中,所有值都存儲在 32 位的單元中,每個單元包含一個小的**類型標(biāo)簽(1-3 bits)**以及當(dāng)前要存儲值的真實數(shù)據(jù)。類型標(biāo)簽存儲在每個單元的低位中,共有五種數(shù)據(jù)類型:
- 000: object - 當(dāng)前存儲的數(shù)據(jù)指向一個對象。
- 1: int - 當(dāng)前存儲的數(shù)據(jù)是一個 31 位的有符號整數(shù)。
- 010: double - 當(dāng)前存儲的數(shù)據(jù)指向一個雙精度的浮點數(shù)。
- 100: string - 當(dāng)前存儲的數(shù)據(jù)指向一個字符串。
- 110: boolean - 當(dāng)前存儲的數(shù)據(jù)是布爾值。
如果最低位是 1,則類型標(biāo)簽標(biāo)志位的長度只有一位;如果最低位是 0,則類型標(biāo)簽標(biāo)志位的長度占三位,為存儲其他四種數(shù)據(jù)類型提供了額外兩個 bit 的長度。
有兩種特殊數(shù)據(jù)類型:
- undefined(JSVAL_VOID) 的值是 -2**30(-2 的 30 次方) (一個超出整數(shù)范圍的數(shù)字)
- null(JSVAL_NULL) 的值是機器碼 NULL 指針(null 指針的值全是 0)。或者:object 類型的類型標(biāo)簽 + 0 的引用。
現(xiàn)在可以很明顯地知道為什么 typeof 操作符會認為 null 是對象了:typeof 操作符檢測 null 的類型標(biāo)簽位時發(fā)現(xiàn)是 000 (存放機器碼 NULL 指針的存儲單元中的所有數(shù)據(jù)位都是 0,所以低三位也是 0)。下面是 typeof 操作符的機器碼:
JS_PUBLIC_API(JSType)JS_TypeOfValue(JSContext *cx, jsval v){JSType type = JSTYPE_VOID;JSObject *obj;JSObjectOps *ops;JSClass *clasp;CHECK_REQUEST(cx);if (JSVAL_IS_VOID(v)) { // (1) 檢查是否為 undefinedtype = JSTYPE_VOID;} else if (JSVAL_IS_OBJECT(v)) { // (2) 檢查是否為 object(低三位是 000)obj = JSVAL_TO_OBJECT(v);if (obj &&(ops = obj->map->ops,ops == &js_ObjectOps? (clasp = OBJ_GET_CLASS(cx, obj),clasp->call || clasp == &js_FunctionClass) // (3,4): ops->call != 0)) { // (3) 檢查是否為函數(shù)type = JSTYPE_FUNCTION;} else {type = JSTYPE_OBJECT;}} else if (JSVAL_IS_NUMBER(v)) { // 檢查是否為數(shù)字type = JSTYPE_NUMBER;} else if (JSVAL_IS_STRING(v)) { // 檢查是否為字符串type = JSTYPE_STRING;} else if (JSVAL_IS_BOOLEAN(v)) { // 檢查是否為布爾值type = JSTYPE_BOOLEAN;}return type;} 復(fù)制代碼上面代碼的運行步驟:
- 在步驟(1)中,機器首先檢查值 v 是否是 undefined (VOID)。該檢查是通過比較值是否相等來完成的:
- 步驟(2)檢查值是否具有 object 類型的類型標(biāo)簽。如果該值具有 object 類型的類型標(biāo)簽,并可以調(diào)用(3)或者其內(nèi)部屬性 [[Class]] 標(biāo)記它為函數(shù)(4),則該值是一個函數(shù);否則,該值就是一個對象。這就是 typeof null 表達式生成的結(jié)果。
- 隨后檢查分別為是否為 number,string 以及 boolean。甚至沒有專門的步驟來檢查是否為 null,該檢查可通過如下的 C 宏定義來實現(xiàn):
這或許看起來是一個非常明顯的 bug,但是不要忘了實現(xiàn) JavaScript 第一個版本的時間非常緊迫。
鳴謝:感謝 Tom Schuster(@evilpies) 指引我去看傳統(tǒng) JavaScript 的源碼。
Source Link ?
- The history of “typeof null”
本文翻譯自 Dr. Axel Rauschmayer 的博文,侵刪。
轉(zhuǎn)載請聯(lián)系作者并注明出處。
Translator Info ?
- GitHub
- Email: web.taox@gmail.com
總結(jié)
以上是生活随笔為你收集整理的【译】Typeof null 的历史的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL Server配置delegati
- 下一篇: 2018,抢票大作战