型別(types)相當於特徵,它們代表值(value)的行為。
譬如,開發者可以使用不同的方式處理89
這個值。如果希望做算術運算,89
的型別為(number);若只單純存顯示於頁面上,此時89
的型別可以為(string),端看開發者需要對值做何種的處理,而有不同的型別表示。
撰寫程式碼的過程當中,時常會用到型別轉換,尤其是JS會以自己的方式去處理值的強制轉型(value coercion),為避免強制轉型將值轉換成非預期的結果,所以了解每個型別相當重要。
譬如,型別為(number)的值89
,當我們希望以字串的行為來處理這個值的時候,該值就必須先轉型為(string),此時就可以取出位置為1的"9"這個字串。
JS內建7大型別(built-in types)
除了object之外,其他型別均為基本型別值(primitives)。
typeof
運算子,會以字串的形式回傳值的型別。
需要特別注意的是null
。
如果使用typeof
,會產生出乎意料的結果:
若需要確認型別是否為null
,需使用複合條件。
null
是唯一個「falsy」的基型值。
那如果檢查function呢?
這時會有個疑問是,型別顯示function,但剛剛所提及的型別並沒有function。
實際上function在JS中是屬於object。
進一步的說,function是一個擁有[ [ Call ] ]內部特性,可以被呼叫的物件(callable object)。
既然function是object,所以也會擁有屬性(properties)。
function a有一個length
屬性,代表宣告參數的數目。
那陣列(array)呢?
陣列也是object,具有2大特點:
1.
以數值化的方式索引,普通物件只能以字串為鍵值。
例如我們要取a陣列的第1個元素,可以使用a[0]的方式。
如若要取a物件的p屬性,要使用a.p或是a['p']。
2.
會自動更新維護length
屬性。隨著陣列元素的增加或減少,我們無須重新指定length
屬性的值,JS會自動計算當下陣列所有的元素數量。
在JS中,變數(variables)沒有型別,值(value)才有型別。
變數可以隨時擁有任的的值。
JS並非強型別的程式語言,當我們宣告一個變數持有string型別的值,下一個敘述句,此變數可以持有number,這在JS中是合法的。
89
這個值的型別是number,其型別無法改變,我們可以透過強制轉型(coercion)的方式,再另外建立一個型別為string的值"89"。
使用typeof
的時候,表面上看似確認該變數的型別為何。
更為洽當的說法是,該變數所持有的那個值的型別為何。
已宣告(declared),但未設定初始值的變數,預設值為undefined。
使用typeof
會回傳"undefined"。
未定義(undefined) & 未宣告(undeclared)實質上的差異
「undefined」表示在範疇中已經被宣告的變數,當下並沒有其他的值,預設就是會給undefined。
注意,undefined也是一個值。
「undeclared」表示在範疇中並未宣告變數。
瀏覽器的錯誤訊息是「b is not defined」,乍看之下似乎跟「undefined」一樣,但實際上這是兩種不同的情況,「b is not defined」錯誤訊息所代表的意思,等同於「undeclared」,並非「undefined」。
typeof
使用於未宣告的變數會產生特別的行為:
請注意,b並未被宣告,執行typeof b的時候,沒有錯誤被擲出,這是typeof的特殊防護機制。
假設我們有一支debug.js程式,在其頂層宣告var DEBUG= true
,藉此控制是否進入debug模式。
這支程式只會在開發過程載入,實際上線不會載入。
使用以下方式會擲出ReferenceError。
if (DEBUG) {
console.log('Debugging is starting');
}
如果透過typeof
的特性可以安全地檢查
if (typeof DEBUG !== "undefined") {
console.log('Debugging is starting');
}
另一種不使用typeof
的特性,對於全域變數做檢查,改從「所有的全域變數都是全域物件的屬性」這個觀點著手。
所以可以改成:
if (window.DEBUS) {
//...
}
嘗試存取一個不存在的物件屬性不會擲出ReferenceError。
另一種情境是,當需要在別人的程式碼中套入我們撰寫的程式碼,想要先檢查他人的程式碼是否有包含我們要使用的特定變數時,可以使用下列方式處理:
function doSomethingCool() {
var helper = (typeof FeatureXYZ !== "undefined") ? FeatureXYZ : function () {};
var val = helper();
}
doSomethingCool()
會先檢查是否有FeatureXYZ
這個變數,如果有,就使用;如果沒有,就用我們自己的版本。
跟剛剛範例不同的是,FeatureXYZ
是區域變數,不是全域變數,但我們依然可以使用typeof
來做安全檢查。
相同的情境,也可以使用「相依注入(dependency injection)」的方式。
function doSomethingCool(FeatureXYZ) {
var helper = FeatureXYZ || function () {}
var val = helper();
}
以FeatureXYZ變數作為引數,再利用OR( || )的特性,檢查FeatureXYZ是否存在。
此為You Don't Know JS系列的筆記。