首頁  >  文章  >  web前端  >  JavaScript 的 typeof 的用途

JavaScript 的 typeof 的用途

高洛峰
高洛峰原創
2016-11-26 16:07:58959瀏覽

JavaScript 中的 typeof 其實非常複雜,它可以用來做很多事情,但同時也有很多怪異的表現。 本文列舉出了它的多個用法,而且也指出了存在的問題以及解決方案。

 

閱讀本文的前提是,你現在應該已經知道原始值和物件值的差別了。

 

檢查一個變數是否存在,是否有值

typeof在兩種情況下會回傳"undefined":

 

變數沒有被宣告

:

 

> typeof undeclaredVariable === "undefined"

tru​​e

 

> var declaredVariable;

> typeof undefined

'undefined'

還有其他辦法偵測某個值是否為undefined:

 

> var value = undefined;

> value === undefined

tru​​e

但如果使用這種方法在一個未宣告的變數上會拋出異常,因為只有typeof 才可以正常檢測未聲明的變數的同時還不報錯:

 

> undeclaredVariable === undefined

ReferenceError: undeclaredVariable undefined

ReferenceError: undeclaredVariable undefined

ReferenceError: undeclaredVariable isabled被傳入參數的形參,不存在的屬性,都不會出現上面的問題,因為它們總是可訪問的,值總是undefined:

 

> var declaredVariable;

> declaredVariable === undefined

tru​​e

 

> (function (x) { return x === undefined }())

tru​​e

 :因此,如果想要偵測一個可能沒有被宣告的全域變數是否存在,也可以使用if(window.maybeUndeclaredVariable){}。

 

問題:typeof 在完成這樣的任務時顯得很繁雜.

 

解決辦法:這樣的操作不是很常見,所以有人覺的沒必要再找更好的解決辦法了。 不過也許有人會提出一個專門的操作符:

 

> defined undeclaredVariable

false

 

> var deccariable;有人還需要一個檢測變數是否被陳述的操作符:

 

> declared undeclaredVariable

false

 

> var declaredVariable;Voperal

,上面的defined 運算子相當於defined( ),上面的declared 運算子相當於exists()。

 

判斷一個值不等於undefined 也不等於null

問題:如果你想檢測一個值是否被定義過(值不是undefined 也不是null),那麼你就遇到了typeof 最有名的一個怪異表現(被認為是一個bug):typeof null 回傳了"object":

 

> typeof null 

'object'

譯者註:這只能說是最初的JavaScript 實現的bug,而現在標準就是這樣規範的。 V8 曾經修正並實現過 typeof null === "null",但最終證明不可行。 http://wiki.ecmascript.org/doku.php?id=harmony:typeof_null。

 

(翻譯:typeof 在操作null 時會返回"object",這是JavaScript 語言本身的bug。不幸的是,這個bug 永遠不可能被修復了,因為太多已有的程式碼已經依賴了這樣的表現。方法:不要用typeof 來做這項任務,用下面這樣的函數來取代:

 

function isDefined(x) {

    return x !== null && x !== undefine

    return x !== null && x !== undefine

    return x !== null && x !== undefined;一個可能性是引入一個“預設值運算子”,在myValue 未定義的情況下,下面的表達式會返回defaultValue:

 

myValue ?? defaultValue

上面的表達式等價於:

 

(myValue !== undefined && myValue !== null) ? myValue : defaultValue

又或:

 

myValue ??= defaultValue

??defaultValue

當你存取一個嵌套的屬性時,例如bar,你或許會需要這個運算子的幫助:

 

obj.foo.bar

如果objobj.foo 是未定義的,上面的表達式會拋出異常。 一個運算子.?? 可以讓上面的表達式在遍歷一層一層的屬性時,傳回第一個遇到的值為undefined 或null 的屬性:

 

obj.??foo.??bar??foo.??bar??

上面的表達式等價於:

 

(obj === undefined || obj === null) ? obj

    : (obj.foo === undefined || obj.foo === null) ? obj.foo

        : obj.foo.bar

是否使用是物件值:

 

function isObject(x) {

    return (typeof x === "function"

          

}

問題:上面的偵測比較複雜,是因為typeof 把函數和物件看成是不同的類型,而且typeof null 回傳"object".

 

解決方法:下面的方法也常用於偵測物件值:

 

function isObject2(x) {

    return x === Object(x);

}

警告:你也許認為這裡可以使用instance instance 來偵測的原型來判斷實例關係的,那麼沒有原型的物件怎麼辦呢:

 

> var obj = Object.create(null);

> Object.getPrototypeOf(obj)

> Object.getPrototypeOf(obj)

對象,但它不是任何值的實例:

 

> typeof obj

'object'

> obj instanceof Object

false

存在,而且有它的用途。

 

譯者註:Object.prototype 就是唯一的一個內建的,沒有原型的物件。

 

>Object.getPrototypeOf(Object.prototype)

null

>typeof Object.prototype

'object'

typeof 是最好的用來查看某個原始值的類型的方式。

 

> typeof "abc"

'string'

> typeof undefined

'undefined'

問題:你必須知道 typeof null 的怪異表現。

 

> typeof null  // 要小心!

'object'

解決方法:下面的函數可以修復這個問題(只針對這個用例)。

 

function getPrimitiveTypeName(x) {

    var typeName = typeof x;

    switch(typeName) {  case "boolean":

        case "number":

        case " string":

            return typeName;

        case "object":

     return "null";

            }

        default: // 前面的判斷皆未通過

throw new TypeError("參數不是原始值: "+x);

    }

}

更好的解:實作一個函數getTypeName(),除了可以傳回原始值的的型別,還可以傳回物件值的內部[[Class]] 屬性。 這裡講如何實現這個函數(譯者註:jQuery 中的 $.type 就是這樣的實作)

 

某個值是否是函數

typeof 可以用來偵測一個值是否是函數。

 

> typeof function () {}

'function'

> typeof Object.prototype.toString

'function'instance

乍一看,似乎寫法更優雅。 但是,瀏覽器有一個怪癖:每個框架和視窗都有它自己的全域變數。 因此,如果你將某個框架中的物件傳到另一個框架中,instanceof 就無法正常運作了,因為這兩個框架有著不同的建構子。 這就是為什麼 ECMAScript5 中會有Array.isArray() 方法的原因。 如果有一個能夠跨框架的,用於檢查一個物件是否是給定的建構函數的實例的方法的話,那會很好。 上述的 getTypeName() 是一個可用的變通方法,但也許還有一個更根本的解。

 

綜述

下面提到的,應該是目前 JavaScript 中最迫切需要的,可以代替一些typeof 目前職責的功能特性:

 

isDefined() (比如Object.isDefined()): 可以作為一個函數或運算子

 

isObject()

 

getTypeName()

 

是否已經被聲明這樣的需求,可能沒那麼必要有自己的運算子。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn