第一章 型別

王工發表於2016-04-26

定義

許多開發者認為動態語言沒有型別。然並卵!本文對“型別”(Type)的定義為:

一種語言中具有固有特性的值,能從行為上區分與其他值是不同的,直譯器與人都能理解這種區別。

型別為什麼如此重要

只有瞭解型別的固有特性,才能知道如何恰當的對其強制轉型(Coercion)(見 第四章 強制轉型),而且JS ( JavaScript )的轉型有時候非常詭異,許多開發者認為這是JS語言的糟粕因此敬而遠之,只有深入瞭解了JS的型別(Types)與值(Values)之後,才能真正理解和發揮強制轉型的威力。

內建型別(Build-in Types)

JS中有7(6+1)種內建型別

  1. string
  2. boolean
  3. number
  4. object (包括Function Array Date Error RegExp String Boolean Number )
  5. null
  6. undefined
  7. symbol (es6新加入,詳見 第三章 )

而檢視內建型別的方法就是 typeof ,返回一個字串

typeof "string";  //=> "string"
typeof 1;  //=> "number"
typeof null; //=> "object"

關於null的bug,這個歷史遺留問題,判斷null的方法

!null && typeof null === "object"; // true

既然 typeof 不能顯示 null,那是不是typeof 只能返回6種型別呢?答案當然是錯啦,因為還有

typeof function(){};  //=> "function"
typeof Function;  //=> "function"
typeof [];  //=> "object"

簡直嗶了狗了,同樣是物件,函式憑什麼就比陣列等另外6物件子類高階,還佔了一個 typeof ! 道理我們都懂,就是因為函式作為物件的子型別,有個隱藏的 [[Call]] 屬性,函式就是一個可以呼叫的物件,然而另外6物件子類並沒有這種待遇。

跑題1 關於 function 與 另外6物件子類的區別

既然function 與 另外6物件子類 都是物件,那就可以看看物件都有哪些屬性

var foo = function (a,b,c) {};
var arr = [1,2,3];
Object.keys(foo)  //=> []
Object.keys(arr)  //=> ["0", "1", "2"]

WTF!! 為什麼沒有屬性?因為Object.keys()只能返回可列舉屬性,而不可列舉屬性需要用Object.getOwnPropertyNames()獲取

Object.getOwnPropertyNames(foo)  //=> ["length", "name", "arguments", "caller", "prototype"]
Object.getOwnPropertyNames(arr)  //=> ["0", "1", "2", "length"]
Object.getOwnPropertyNames(/1/) //=> ["lastIndex"]
Object.getOwnPropertyNames(new Error())  //=> ["stack"]
...等

這次總算出來了,用chrome開發者工具 console.dir(foo) 看下是這樣的:

enter image description here

可是這些屬性有什麼卵用呢?目前只知道函式的length屬性是引數的數量,name屬性是函式的名字,prototype不用說了(見 YDKJS第二本書),其他的到底是什麼鬼?誰能告訴我。

值(Values)與型別(Types)

在JS中,變數(Variables)是沒有型別,變數只是個盒子,裡面放著值,值才有型別。也就是說JS不會認為一個變數只能儲存同一種型別的值。而值的型別是不會改變的,通過某種方法把一種型別轉換並返回另一種型別的值的過程叫 強制轉型(Coercion)(見 第四章

undefined 與 未宣告(undeclared)

undefined 的字面意思是“未宣告”,然而 undefined 在 JS 中與 "string"、1、{a:1}、true 這些內建型別一樣,也是一種值的型別,只不過它就是叫 undfined。

比如:

var a; 
a //=> undefined
b //=> Uncaught ReferenceError: b is not defined

我的理解是 a 作為一個變數,相當於告訴JS我有一個叫“a”的盒子,但是並沒有賦值,而這個盒子裡自帶了一個叫 undefined 的值,而我並沒有告訴JS我有一個叫 “b”的盒子,所以會報錯,因為JS找不到這個叫“b”的盒子,所以a就是宣告但未賦值,自帶undefined值的盒子,而b就是未宣告的盒子。

使用 typeof 檢查未宣告變數

之前 b 作為沒有宣告的變數,如果在編寫程式碼時不小心用到了 b ,就會導致報錯,程式中斷,而使用typeof可以避免這個問題

typeof b; //=> "undefined"

WTFFFF! 這到底什麼鬼,說好的未宣告的變數 b,為什麼用typeof檢測它會出現 undefined !! 雖然不知道為什麼,但是可以利用這個特性來檢查是否有變數已經被宣告過了,因為有時候你需要載入多個JS檔案,萬一別人宣告過的變數你也想用怎麼辦呢,就可以用 typeof 檢查一下。

雖然使用全域性變數是非常不好的行為,但是...書上就是這麼舉例的,如果誰有更好的例子麻煩告訴我,謝謝。

本章小結

  1. JS 有 7 種內建型別
  2. typeof 可以顯示JS中值的型別,function雖然不是內建型別,但 typeof 會顯示它,null是一種內建型別,typeof卻會顯示它為“object”。也就是說 typeof 不是一個女子方法,怪不得JS被認為有很多糟粕。
  3. undefined 與 未宣告 是不一樣的,undefined 是一種內建型別,未宣告是從來沒出現過的變數
  4. 可以用 typeof 檢查未宣告變數,這樣可以避免觸發引用錯誤

相關文章