iT邦幫忙

1

【You Don't Know JS: Types & Grammar】Chapter 1 筆記

WM 2019-02-20 23:59:37479 瀏覽

型別(types)相當於特徵,它們代表值(value)的行為。

譬如,開發者可以使用不同的方式處理89這個值。如果希望做算術運算,89的型別為(number);若只單純存顯示於頁面上,此時89的型別可以為(string),端看開發者需要對值做何種的處理,而有不同的型別表示。

撰寫程式碼的過程當中,時常會用到型別轉換,尤其是JS會以自己的方式去處理值的強制轉型(value coercion),為避免強制轉型將值轉換成非預期的結果,所以了解每個型別相當重要。

譬如,型別為(number)的值89,當我們希望以字串的行為來處理這個值的時候,該值就必須先轉型為(string),此時就可以取出位置為1的"9"這個字串。

內建型別

JS內建7大型別(built-in types)

  • null
  • undefined
  • boolean
  • number
  • string
  • object
  • symbol (ES6新增)

除了object之外,其他型別均為基本型別值(primitives)。

typeof運算子,會以字串的形式回傳值的型別。
https://ithelp.ithome.com.tw/upload/images/20190220/20112573TbIdTgstWU.jpg

需要特別注意的是null

如果使用typeof,會產生出乎意料的結果:
https://ithelp.ithome.com.tw/upload/images/20190220/20112573U2Eekcj4tx.jpg

若需要確認型別是否為null,需使用複合條件。
https://ithelp.ithome.com.tw/upload/images/20190220/20112573lRJSWC43lO.jpg

null是唯一個「falsy」的基型值。

那如果檢查function呢?
https://ithelp.ithome.com.tw/upload/images/20190220/20112573ULMQwyXeb4.jpg

這時會有個疑問是,型別顯示function,但剛剛所提及的型別並沒有function。

實際上function在JS中是屬於object。

進一步的說,function是一個擁有[ [ Call ] ]內部特性,可以被呼叫的物件(callable object)。

既然function是object,所以也會擁有屬性(properties)。
https://ithelp.ithome.com.tw/upload/images/20190220/201125733Ysveu2v3Y.jpg

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的時候,表面上看似確認該變數的型別為何
更為洽當的說法是,該變數所持有的那個值的型別為何
https://ithelp.ithome.com.tw/upload/images/20190220/20112573HjaxOeK369.jpg

未定義(undefined) & 未宣告(undeclared)

已宣告(declared),但未設定初始值的變數,預設值為undefined。
https://ithelp.ithome.com.tw/upload/images/20190220/20112573U3OTreY0rz.jpg

使用typeof會回傳"undefined"。

https://ithelp.ithome.com.tw/upload/images/20190220/201125735D0dZKDEWO.jpg

未定義(undefined) & 未宣告(undeclared)實質上的差異

  • 「undefined」表示在範疇中已經被宣告的變數,當下並沒有其他的值,預設就是會給undefined。
    注意,undefined也是一個值。

  • 「undeclared」表示在範疇中並未宣告變數。

https://ithelp.ithome.com.tw/upload/images/20190220/20112573rKjjSxs46x.jpg

瀏覽器的錯誤訊息是「b is not defined」,乍看之下似乎跟「undefined」一樣,但實際上這是兩種不同的情況,「b is not defined」錯誤訊息所代表的意思,等同於「undeclared」,並非「undefined」。

typeof使用於未宣告的變數會產生特別的行為:
https://ithelp.ithome.com.tw/upload/images/20190220/20112573dRYkIOPnYG.jpg

請注意,b並未被宣告,執行typeof b的時候,沒有錯誤被擲出,這是typeof的特殊防護機制。

type Undefined的安全機制

假設我們有一支debug.js程式,在其頂層宣告var DEBUG= true,藉此控制是否進入debug模式。

這支程式只會在開發過程載入,實際上線不會載入。

使用以下方式會擲出ReferenceError。

if (DEBUG) {
    console.log('Debugging is starting');
}

https://ithelp.ithome.com.tw/upload/images/20190220/20112573FIPI0UpMiK.jpg

如果透過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是否存在。

關於OR( || )特性的說明

參考來源:
https://ithelp.ithome.com.tw/upload/images/20190221/201125739FY75WdXxA.jpg

此為You Don't Know JS系列的筆記。


尚未有邦友留言

立即登入留言