第一章 型別
定義
許多開發者認為動態語言沒有型別。然並卵!本文對“型別”(Type)的定義為:
一種語言中具有固有特性的值,能從行為上區分與其他值是不同的,直譯器與人都能理解這種區別。
型別為什麼如此重要
只有瞭解型別的固有特性,才能知道如何恰當的對其強制轉型(Coercion)(見 第四章 強制轉型),而且JS ( JavaScript )的轉型有時候非常詭異,許多開發者認為這是JS語言的糟粕因此敬而遠之,只有深入瞭解了JS的型別(Types)與值(Values)之後,才能真正理解和發揮強制轉型的威力。
內建型別(Build-in Types)
JS中有7(6+1)種內建型別
- string
- boolean
- number
- object (包括Function Array Date Error RegExp String Boolean Number )
- null
- undefined
- 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) 看下是這樣的:
可是這些屬性有什麼卵用呢?目前只知道函式的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 檢查一下。
雖然使用全域性變數是非常不好的行為,但是...書上就是這麼舉例的,如果誰有更好的例子麻煩告訴我,謝謝。
本章小結
- JS 有 7 種內建型別
- typeof 可以顯示JS中值的型別,function雖然不是內建型別,但 typeof 會顯示它,null是一種內建型別,typeof卻會顯示它為“object”。也就是說 typeof 不是一個女子方法,怪不得JS被認為有很多糟粕。
- undefined 與 未宣告 是不一樣的,undefined 是一種內建型別,未宣告是從來沒出現過的變數
- 可以用 typeof 檢查未宣告變數,這樣可以避免觸發引用錯誤
相關文章
- PL/SQL第一章--概述及變數型別SQL變數型別
- 簡單理解js閉包、型別引用....第一章JS型別
- TS資料型別:型別別名/聯合型別/字面量型別/型別推論等綱要資料型別
- 淺談程式語言型別的強型別,弱型別,動態型別,靜態型別型別
- javascript基本型別 引用型別 基本包裝型別JavaScript型別
- C#的型別——值型別與引用型別C#型別
- 值型別和引用型別型別
- JavaScript引用型別-Object型別JavaScript型別Object
- mysql BLOB型別 TEXT型別MySql型別
- 值型別與引用型別型別
- 《Python小白入門第一章》之 變數、資料型別、運算子、註釋Python變數資料型別
- js基本型別和引用型別區別JS型別
- 值型別與引用型別的區別型別
- JAVA 基本型別與 引用型別區別Java型別
- typeScript 型別斷言、聯合型別和交叉型別(七)TypeScript型別
- JavaScript值型別和引用型別JavaScript型別
- c#:值型別&引用型別C#型別
- ECMAScript 原始型別與引用型別型別
- [譯] Scala 型別的型別(四)型別
- [譯] Scala 型別的型別(二)型別
- [譯] Scala 型別的型別(三)型別
- [譯] Scala 型別的型別(六)型別
- [譯] Scala 型別的型別(五)型別
- Date型別和Regex型別型別
- 匿名型別是不是強型別?型別
- Swift值型別和引用型別Swift型別
- 型別預設和any型別型別
- 資料型別,型別轉換資料型別
- C#變數型別(1):引用型別和值型別 (轉)變數型別
- 第一章 熟悉Objective-C—第4條:多用型別常量,少用#define預處理指令Object型別
- 型別 VS 泛型型別泛型
- TypeScript 泛型型別TypeScript泛型型別
- JavaScript - 基本型別與引用型別值JavaScript型別
- Java的基本型別和引用型別Java型別
- 基本資料型別與字串型別資料型別字串
- LONG型別遷移到LOB型別(三)型別
- LONG型別遷移到LOB型別(二)型別
- LONG型別遷移到LOB型別(一)型別