你不知道的js讀後感-型別

Escape_Master發表於2019-03-13

前言

最近找時間讀了"你不知道的javascript",公司導師要求應該要有一些產出,所以隨筆記錄下。順便完善下自己的知識結構體系。但我讀的順序卻很奇葩,從中再到上,最後再讀下,最近又聽了winter的重學前端,所以文章講述的順序可能與書目錄的順序不一致並且夾雜一下其他的感悟。

正文

內建型別

  • 數字(number)
  • 字串(string)
  • 布林值(boolean)
  • 未定義(undefined)
  • 空值(null)
  • 物件(object)
  • 符號(symbol -> ES6)

我們可以使用 typeof 運算子來檢視值的型別,但這七種型別和它們的字串值並不是一一對應的, 以下是其中特殊的個例:

typeof null === 'object'; // true

問題來了,我們期待的結果應該是

typeof null === 'null'; // true

書中明確給出了答案。實際上這是一個 js 存在了將近20年的 bug,也許永遠都不會修復,因為牽涉太多的 web 系統,一旦修復可能導致更多bug,使這些系統無法正常的工作。

同時書中也給出了用複合條件檢測null的型別:

var a = null;
(!a && typeof a === "object"); // true
null 是基本型別中唯一的一個“假值”型別typeof對它返回值是'object'
複製程式碼

還有一種情況:

typeof function a(){ /* .. */ } === "function"; // true

看起來, function 函式應該也是一個內建型別, 但實際上它是 object 的一個 "子型別";

具體來說, 函式是 "可呼叫的物件", 它有一個內部屬性 [[call]], 該屬性使其能夠被呼叫;

既然函式是物件, 那麼它就應該有自己的屬性:

function test(a, b, c) {
    /* .. */
}
test.length // 3
因為該函式宣告瞭三個命名引數,a、b 和 c,所以其 length 值為 3

複製程式碼

可以看到, 函式的 length 屬性指的是其引數的個數

再來看看陣列。JavaScript 支援陣列,那麼它是否也是一個特殊型別?

typeof [] === 'object'; // true
// 陣列也是物件, 它是 object 的一個子型別,陣列的元素按數字順序來進行索引(而非普通像物件那樣通過字串鍵值),其 length 屬性是元 素的個數。
複製程式碼

typeof

typeof 運算子總是會返回一個字串

typeof typeof 42; // string
複製程式碼

該表示式, 首先會執行 typeof 42 返回字串 number, 再執行 typeof 'number', 返回 string

值和型別

JavaScript 中的變數是沒有型別的,只有值才有。變數可以隨時持有任何型別的值。 也就是說, 語言引擎不要求變數總是持有與其初始值同型別的值, 我們可以隨時修改變數的值的型別:

var a = 1;
typeof a === 'number' //true
a = "1"
typeof a === 'string' //true
複製程式碼

undefined 和 undeclared

undefined 即變數已被宣告, 但未被賦值,undeclared 即沒在作用域中宣告過的變數;

訪問已宣告但未賦值的變數 (undefined), 瀏覽器會返回 undefined; 訪問從未在作用域中宣告的變數 (undeclared), 則會丟擲錯誤:

var a;
console.log(a) // undefined
console.log(b) // ReferenceError: b is not defined
複製程式碼

上例中,“b is not defined”容易讓人誤以為是“b is undefined”。此時如果瀏覽器 報錯成“b is not found”或者“b is not declared”會更準確。

再舉個typeof的?

var a;
typeof a; // "undefined"
typeof b; // "undefined"
複製程式碼

所以要引出一個typeof的安全防範機制的概念

typeof 的安全機制

該安全防範機制對在瀏覽器中執行的 JavaScript 程式碼來說還是很有幫助的,因為多個指令碼 檔案會在共享的全域性名稱空間中載入變數。

舉個?

我們有一個變數叫做 DEBUG, 該變數存放在 dev.js 中, 該 js 檔案只會在開發環境被呼叫, 我們需要在另一個 js 檔案中判斷 DEBUG 變數是否存在, 而進行接下來的操作

// app.js
if (DEBUG) {
  /* ... */
}
複製程式碼

如上程式碼, 如果在生產環境, 瀏覽器肯定會丟擲異常 ReferenceError: DEBUG is not defined, 從而阻斷 js 的執行;

這種情況, 我們就可以通過 typeof 的安全機制來解決這個問題:

if (typeof DEBUG !== 'undefined') {
  /* ... */
}
複製程式碼

小結

JavaScript 有 七 種 內 置 類 型:null、undefined、boolean、number、string、object 和 symbol,可以使用 typeof 運算子來檢視。

變數沒有型別,但它們持有的值有型別。型別定義了值的行為特徵。

很多開發人員將 undefined 和 undeclared 混為一談,但在 JavaScript 中它們是兩碼事。 undefined 是值的一種。undeclared 則表示變數還沒有被宣告過。

遺憾的是,JavaScript 卻將它們混為一談,在我們試圖訪問 "undeclared" 變數時這樣報 錯:ReferenceError: a is not defined, 並 且 typeof 對 undefined 和 undeclared 變 量 都 返 回 "undefined"。

然而,通過 typeof 的安全防範機制(阻止報錯)來檢查 undeclared 變數,有時是個不錯的 辦法。


感悟

第一章給我的感覺是知識的範圍不是特別廣,所以特意讀了winter的重學前端,winter開篇就提出了幾個問題。如下:

  • 為什麼有的程式設計規範要求用 void 0 代替 undefined
  • 字串有最大長度嗎
  • 0.1 + 0.2 不是等於 0.3 麼?為什麼 JavaScript不是這樣的
  • ES6的symbol是個什麼玩應兒
  • 為什麼給物件新增的方法能用在基本型別上?

後續文章結合於此書沒有給出的知識點給出這些問題的答案~

希望大家都能找到適合自己的學習方法重學前端,完善自己的知識體系架構~

相關文章