前言
因緣際會之下,我得到了更多學習 JavaScript 的機會,覺得這很適合成為 JavaScript Weird 的一個支線,大概就很像打遊戲一樣,同樣的關卡還有個裏關。因此所謂的支線呢,就是把之前篇章提到的某些概念再拿出來寫一次,但是記錄的觀點不一樣,希望透過這樣的方式,能讓自己理解更多。
變數的資料型態
變數的資料型態總共有七種:
JavaScript 有六種純值 (Primitive Types,或稱為基本型別、原始型態)
- null
- undefined
- string
- number
- boolean
- sysbol ( ES6 )
其他都是物件
- object (像是 array , function , date … )
如何判斷型態
最簡單的方式就是使用「typeof」,先把每個型態都印出來瞧瞧:
1 | console.log(typeof 10); // number |
這邊故意用了一行空白隔開,上半部是比較好理解的,因為那些的確就是它們的型態,可是下面的部分呢?
為什麼陣列的型態會是物件 ?
- 這部分也能參考 [JavaScriptWeird]No.42 所有東西都是物件或純值
1
2
3
4var a = [];
console.log(a.__proto__);
console.log(a.__proto__.__proto__);
console.log(a.__proto__.__proto__.__proto__); // null
可以像這樣透過觀察原型的方式得知, array 的最底層也是物件。
同理也可以觀察函式,會得出函式也是物件。
最特別的是 null ,為什麼 null 的型別會是 object ?
其實這是 JavaScript 最廣為人知的 BUG ,MDN 上也有相關的記載,聽說是從一開始就存在了,但可能是有牽扯到很多東西,所以沒有人去修正。
MDN 也幫我們整理好了 typeof
的表格,真的是非常給力。
如何更精準的判斷型態
雖然大多數的情況, typeof
已經夠用了,但如果我希望如果它的型態就是 array 而不是回傳 object 的話,還有什麼方式?
- 可以使用 Array.isArray() 方法,如環境不支援 MDN 內也有 Polyfill
1 | var a = []; |
1 | var a = []; |
常見的 typeof 用法
還記得運算子的優先性與相依性嗎?typeof 是運算子,查詢表格後得知是右相依性 (right-to-left),常見的做法像是「檢查某變數有無作用」:
1 | if (typeof a !== 'undefined') { |
透過這樣子寫,當變數 a
不存在的時候什麼都不會發生,存在的時候就會秀出該變數型態。
但問題是為什麼不能直接用「!==」判斷就好 ?
為什麼 typeof
後面可以直接用 a
?
1 | // var a; 沒有這行就出錯 |
就如同先前培養的觀念,如果沒有宣告變數 a
,在全域執行環境內也找不到 a
,這時如果嘗試取用 a
就會跳出錯誤。
然而,為什麼 typeof 就可以呢?
讓我們再次研究運算子的優先性與相依性
- 「typeof」的優先值 16,為右相依性
- 「!==」的優先值 10,為左相依性
優先值高的會先執行,也就是說實際上是「typeof a
」先做了。
typeof
運算子會傳回一個字串值,指出未經運算 (unevaluated) 的運算元所代表的型別,之後才進行「!==」的比較。
Primitive Types 與 object 差別
其中的一個差別就是,Primitive Types 是不可改變 (Immutable) 的,這個「不可改變」不是直觀的那個意思。
1 | // 並不是這個意思 |
這個並不是改變,正確來說這樣叫重新賦值。
所謂的 Primitive Types 不可改變是這樣的:
1 | var str = 'hello'; |
現在 str
是個字串純值,使用了 toUpperCase()
把小寫字母變成大寫字母,但因為純值本身是不可改變的,所以當執行完 toUpperCase()
後, str
本身並沒有改變什麼,所以仍舊是小寫的 hello 。
而「toUpperCase()
」 會做的事情就是取得 str
的字串值後,「回傳」一個大寫的新字串,而不是改變 str
內容。
當然如果改成這樣寫就變成大寫了,因為被重新賦值了。
1 | var str = 'hello'; |
那至於可改變 (mutable) 的 object 是怎麼回事?
1 | var arr = [1]; |
陣列 arr
本身的確被改變了,而且不是藉由等號運算子賦值。
[心得]
正如我前言所說的,覺得這真得很適合做為 JavaScript Weird 的支線,因為講到的觀念其實都蠻進階的,可以看到我時不時穿插了之前做的筆記,但畢竟這算是給初學者的進階 JavaScript ,所以也算是蠻合理的。