[JavaScriptWeird]No.51 變數的資料型態

前言

因緣際會之下,我得到了更多學習 JavaScript 的機會,覺得這很適合成為 JavaScript Weird 的一個支線,大概就很像打遊戲一樣,同樣的關卡還有個裏關。因此所謂的支線呢,就是把之前篇章提到的某些概念再拿出來寫一次,但是記錄的觀點不一樣,希望透過這樣的方式,能讓自己理解更多。

變數的資料型態

變數的資料型態總共有七種:

JavaScript 有六種純值 (Primitive Types,或稱為基本型別、原始型態)

  • null
  • undefined
  • string
  • number
  • boolean
  • sysbol ( ES6 )

其他都是物件

  • object (像是 array , function , date … )

如何判斷型態

最簡單的方式就是使用「typeof」,先把每個型態都印出來瞧瞧:

1
2
3
4
5
6
7
8
9
console.log(typeof 10); // number  
console.log(typeof 'Hi'); // string
console.log(typeof undefined); // undefined
console.log(typeof true); // boolean
console.log(typeof {}); // object

console.log(typeof \[\]); // object
console.log(typeof function(){}); // function
console.log(typeof null); // object

這邊故意用了一行空白隔開,上半部是比較好理解的,因為那些的確就是它們的型態,可是下面的部分呢?

為什麼陣列的型態會是物件 ?

可以像這樣透過觀察原型的方式得知, array 的最底層也是物件。

同理也可以觀察函式,會得出函式也是物件。

最特別的是 null ,為什麼 null 的型別會是 object ?

其實這是 JavaScript 最廣為人知的 BUG ,MDN 上也有相關的記載,聽說是從一開始就存在了,但可能是有牽扯到很多東西,所以沒有人去修正。

MDN 也幫我們整理好了 typeof 的表格,真的是非常給力。

如何更精準的判斷型態

雖然大多數的情況, typeof 已經夠用了,但如果我希望如果它的型態就是 array 而不是回傳 object 的話,還有什麼方式?

1
2
var a = [];  
console.log(Array.isArray(a)); // true
1
2
3
var a = [];  
console.log(Object.prototype.toString.call(a)); // [object Array]
console.log(Object.prototype.toString.call(null)); // [object Null]

常見的 typeof 用法

還記得運算子的優先性與相依性嗎?typeof 是運算子,查詢表格後得知是右相依性 (right-to-left),常見的做法像是「檢查某變數有無作用」:

1
2
3
if (typeof a !== 'undefined') {  
console.log(typeof a);
}

透過這樣子寫,當變數 a 不存在的時候什麼都不會發生,存在的時候就會秀出該變數型態。

但問題是為什麼不能直接用「!==」判斷就好 ?

為什麼 typeof 後面可以直接用 a?

1
2
3
4
// var a; 沒有這行就出錯  
if (a !== 'undefined') {
console.log(typeof a);
}

就如同先前培養的觀念,如果沒有宣告變數 a ,在全域執行環境內也找不到 a ,這時如果嘗試取用 a 就會跳出錯誤。

然而,為什麼 typeof 就可以呢?
讓我們再次研究運算子的優先性與相依性

  • 「typeof」的優先值 16,為右相依性
  • 「!==」的優先值 10,為左相依性

優先值高的會先執行,也就是說實際上是「typeof a」先做了。

typeof 運算子會傳回一個字串值,指出未經運算 (unevaluated) 的運算元所代表的型別,之後才進行「!==」的比較。

Primitive Types 與 object 差別

其中的一個差別就是,Primitive Types 是不可改變 (Immutable) 的,這個「不可改變」不是直觀的那個意思。

1
2
3
// 並不是這個意思  
var a = 1;
a = 2

這個並不是改變,正確來說這樣叫重新賦值。

所謂的 Primitive Types 不可改變是這樣的:

1
2
3
var str = 'hello';  
str.toUpperCase();
console.log(str); // hello

現在 str 是個字串純值,使用了 toUpperCase() 把小寫字母變成大寫字母,但因為純值本身是不可改變的,所以當執行完 toUpperCase() 後, str 本身並沒有改變什麼,所以仍舊是小寫的 hello 。

而「toUpperCase()」 會做的事情就是取得 str 的字串值後,「回傳」一個大寫的新字串,而不是改變 str 內容。

當然如果改成這樣寫就變成大寫了,因為被重新賦值了。

1
2
3
var str = 'hello';  
str = str.toUpperCase();
console.log(str); // HELLO

那至於可改變 (mutable) 的 object 是怎麼回事?

1
2
3
var arr = [1];  
arr.push(2);
console.log(arr); // [1, 2]

陣列 arr 本身的確被改變了,而且不是藉由等號運算子賦值。

[心得]

正如我前言所說的,覺得這真得很適合做為 JavaScript Weird 的支線,因為講到的觀念其實都蠻進階的,可以看到我時不時穿插了之前做的筆記,但畢竟這算是給初學者的進階 JavaScript ,所以也算是蠻合理的。

0%