## 3.1 類型
### 3.1.1 類型
類型:是值的內部特征,它定義了值的行為,以使其區別于其他值。
### 3.1.2 內置類型
JavaScript 有七種內置類型:
? 空值(null)
? 未定義(undefined)
? 布爾值( boolean)
? 數字(number)
? 字符串(string)
? 對象(object)
? 符號(symbol,ES6 中新增)
除對象之外,其他統稱為“基本類型”。
可以用typeof 運算符來查看值的類型,它返回的是類型的字符串值。
~~~
typeof undefined === "undefined"; // true
typeof true === "boolean"; // true
typeof 42 === "number"; // true
typeof "42" === "string"; // true
typeof { life: 42 } === "object"; // true
// ES6中新加入的類型
typeof Symbol() === "symbol"; // true
~~~
null 是基本類型中唯一的一個“假值”類型,typeof對它的返回值為"object"。
~~~
typeof null === "object"; // true
//需要使用復合條件來檢測null 值的類型:
var a = null;
(!a && typeof a === "object"); // true
~~~
function(函數)也是JavaScript 的一個內置類型,它實際上是object 的一個“子類型”,具體來說,函數是“可調用對象”,它有一個內部屬性[[Call]],該屬性使其可以被調用。
~~~
`typeof function a(){ /* .. */ } === "function"; // true`
~~~
函數不僅是對象,還可以擁有屬性。例如:
~~~
function a(b,c) {
/* .. */
}
~~~
函數對象的length 屬性是其聲明的參數的個數:`a.length; // 2`,因為該函數聲明了兩個命名參數,b 和c,所以其length 值為2。
數組也是對象,也是object 的一個“子類型”,數組的元素按數字順序來進行索引(而非普通像對象那樣通過字符串鍵值),其length 屬性是元素的個數。
~~~
typeof [1,2,3] === "object"; // true
~~~
### 3.1.3 值和類型
JavaScript 中的變量是沒有類型的,只有值才有。變量可以隨時持有任何類型的值。換個角度來理解就是,JavaScript 不做“類型強制”;也就是說,語言引擎不要求變量總是持有與其初始值同類型的值。一個變量可以現在被賦值為字符串類型值,隨后又被賦值為數字類型值。
在對變量執行typeof 操作時,得到的結果并不是該變量的類型,而是該變量持有的值的類型,因為**JavaScript 中的變量沒有類型。**
~~~
var a = 42;
typeof a; // "number"
a = true;
typeof a; // "boolean"
~~~
typeof 運算符總是會返回一個字符串:
~~~
typeof typeof 42; // "string"
~~~
typeof 42 首先返回字符串"number",然后typeof "number" 返回"string"。
**1. undefined 和undeclared**
變量在未持有值的時候為undefined。此時typeof 返回"undefined":
~~~
var a;
typeof a; // "undefined"
var b = 42;
var c;
// later
b = c;
typeof b; // "undefined"
typeof c; // "undefined"
~~~
已在作用域中聲明但還沒有賦值的變量,是`undefined` 的。相反,還沒有在作用域中聲明過的變量,是`undeclared` 的。
~~~
var a;
a; // undefined
b; // ReferenceError: b is not defined
~~~
“`undefined`”和“`is not defined`”是兩碼事!
更要注意typeof 處理undeclared 變量的方式:
~~~
var a;
typeof a; // "undefined"
typeof b; // "undefined"
~~~
對于undeclared(或者not defined)變量,typeof 照樣返回"undefined"。請注意雖然b 是一個undeclared 變量,但typeof b 并沒有報錯。這是因為typeof 有一個特殊的安全防范機制。
**2. typeof Undeclared**
該安全防范機制對在瀏覽器中運行的JavaScript 代碼來說還是很有幫助的,因為**多個腳本文件會在共享的全局命名空間中加載變量**。
舉個簡單的例子,在程序中使用全局變量DEBUG 作為“調試模式”的開關。在輸出調試信息到控制臺之前,我們會檢查DEBUG 變量是否已被聲明。頂層的全局變量聲明var DEBUG = true 只在debug.js 文件中才有,而該文件只在開發和測試時才被加載到瀏覽器,在生產環境中不予加載。
問題是如何在程序中檢查全局變量DEBUG 才不會出現ReferenceError 錯誤?
~~~
// 這樣會拋出錯誤
if (DEBUG) {
console.log( "Debugging is starting" );
}
// 這樣是安全的
if (typeof DEBUG !== "undefined") {
console.log( "Debugging is starting" );
}
~~~
這不僅對用戶定義的變量(比如DEBUG)有用,對內建的API 也有幫助:
~~~
if (typeof atob === "undefined") {
atob = function() { /*..*/ };
}
~~~
還有一種不用通過typeof 的安全防范機制的方法,就是檢查所有全局變量是否是全局對象的屬性,瀏覽器中的全局對象是`window`。
~~~
if (window.DEBUG) {
// ..
}
if (!window.atob) {
// ..
}
~~~
與undeclared 變量不同,訪問不存在的對象屬性(甚至是在全局對象window 上)不會產生ReferenceError 錯誤。
如果想讓別人在他們的程序或模塊中復制粘貼你的代碼,就需要檢查你用到的變量是否已經在宿主程序中定義過:
~~~
function doSomethingCool() {
var helper =
(typeof FeatureXYZ !== "undefined") ?
FeatureXYZ :
function() { /*.. default feature ..*/ };
var val = helper();
// ..
}
~~~
其他模塊和程序引入doSomethingCool() 時,doSomethingCool() 會檢查FeatureXYZ 變量是否已經在宿主程序中定義過;如果是,就用現成的,否則就自己定義:
~~~
(function(){
function FeatureXYZ() { /*.. my XYZ feature ..*/ }
// 包含doSomethingCool(..)
function doSomethingCool() {
var helper =
(typeof FeatureXYZ !== "undefined") ?
FeatureXYZ :
function() { /*.. default feature ..*/ };
var val = helper();
// ..
}
doSomethingCool();
})();
~~~
還有一種“依賴注入”(dependency injection)設計模式,就是將依賴通過參數顯式地傳遞到函數中,如:
~~~
function doSomethingCool(FeatureXYZ) {
var helper = FeatureXYZ ||
function() { /*.. default feature ..*/ };
var val = helper();
// ..
}
~~~
- 前言
- 第一章 JavaScript簡介
- 第三章 基本概念
- 3.1-3.3 語法、關鍵字和變量
- 3.4 數據類型
- 3.5-3.6 操作符、流控制語句(暫略)
- 3.7函數
- 第四章 變量的值、作用域與內存問題
- 第五章 引用類型
- 5.1 Object類型
- 5.2 Array類型
- 5.3 Date類型
- 5.4 基本包裝類型
- 5.5 單體內置對象
- 第六章 面向對象的程序設計
- 6.1 理解對象
- 6.2 創建對象
- 6.3 繼承
- 第七章 函數
- 7.1 函數概述
- 7.2 閉包
- 7.3 私有變量
- 第八章 BOM
- 8.1 window對象
- 8.2 location對象
- 8.3 navigator、screen與history對象
- 第九章 DOM
- 9.1 節點層次
- 9.2 DOM操作技術
- 9.3 DOM擴展
- 9.4 DOM2和DOM3
- 第十章 事件
- 10.1 事件流
- 10.2 事件處理程序
- 10.3 事件對象
- 10.4 事件類型
- 第十一章 JSON
- 11.1-11.2 語法與序列化選項
- 第十二章 正則表達式
- 12.1 創建正則表達式
- 12.2-12.3 模式匹配與RegExp對象
- 第十三章 Ajax
- 13.1 XMLHttpRequest對象
- 你不知道的JavaScript
- 一、作用域與閉包
- 1.1 作用域
- 1.2 詞法作用域
- 1.3 函數作用域與塊作用域
- 1.4 提升
- 1.5 作用域閉包
- 二、this與對象原型
- 2.1 關于this
- 2.2 全面解析this
- 2.3 對象
- 2.4 混合對象“類”
- 2.5 原型
- 2.6 行為委托
- 三、類型與語法
- 3.1 類型
- 3.2 值
- 3.3 原生函數