在 JavaScript 中,數組能夠容納任何類型的值,能夠是字符串、數字、對象(object),甚至是其餘數組(多維數組就是經過這種方式來實現的) 。----《你所不知道的JavaScript(中)》P11數據庫
看看下面的代碼:數組
var a = [ 1, "2", [3] ]; a.length; // 3 a[0] === 1; // true a[2][0] === 3; // true var b = [ ]; b.length; // 0 b[0] = 1; b[1] = "2"; b[2] = [ 3 ]; b.length; // 3
對數組聲明後便可向其中加入值,不須要預先設定大小 。有一點須要注意的是使用delete標識符刪除數組元素的時候,數組的長度不變。瀏覽器
var a = [ 1, "2", [3] ]; delete a[0]; // true a.length; // 3 a; // [empty, "2", Array(1)]
在建立「稀疏」數組(sparse array,即含有空白或空缺單元的數組)時也要特別注意:
安全
var a = [ ]; a[0] = 1; // 此處沒有設置a[1]單元 a[2] = [ 3 ]; a[1]; // undefined a.length; // 3
上面的代碼能夠正常運行,但其中的「空白單元」(empty slot)可能會致使出人意料的結果。 a[1] 的值爲 undefined,但這與將其顯式賦值爲 undefined(a[1] = undefined)仍是有所區別。 另外,還有這種狀況,函數
var b = new Array(13); b; // [empty × 13] b.length; // 13
數組經過數字進行索引,但有趣的是它們也是對象,因此也能夠包含字符串鍵值和屬性(但這些並不計算在數組長度內):
工具
var a = [ ]; a[0] = 1; a["foobar"] = 2; a.length; // 1 a["foobar"]; // 2 a.foobar; // 2
數組具備 length 屬性,若是修改其 length 屬性,會修改到數組的值,因此須要特別謹慎,避免修改到數組的 length 屬性。spa
var c = [1,2,3,4,5]; c.length; // 5 c; // [1,2,3,4,5]; c.length = 3; c; // [1,2,3] c.length = 6; c; // [1, 2, 3, empty × 3]
這裏有個問題須要特別注意,若是字符串鍵值可以被強制類型轉換爲十進制數字的話,它就會被看成數字索引來處理。prototype
var a = [ ]; a["13"] = 13; a.length; // 14
字符串和數組的確很類似,都有 length 屬性以及 indexOf(..)(從 ES5開始數組支持此方法)和 concat(..) 方法: 3d
var a = "foo"; var b = ["f","o","o"]; a[1]; // "o"; b[1]; // "o"; a.length; // 3 b.length; // 3 a.indexOf( "o" ); // 1 b.indexOf( "o" ); // 1 var c = a.concat( "bar" ); // "foobar" var d = b.concat( ["b","a","r"] ); // ["f","o","o","b","a","r"] a === c; // false b === d; // false
從上面看雖然字符串和數組的確有不少類似的地方,但這並不意味着它們都是「字符數組」。
調試
JavaScript 中字符串是不可變的,而數組是可變的。而且 a[1] 在 JavaScript 中並不是老是合法語法,在老版本的 IE 中就不被容許(如今能夠了)。 正確的方法應該是 a.charAt(1)。
var a = "foo"; a.length; // 3 a.length = 2; a; // "foo" a.length; // 3 a.charAt(0); // "f"
JavaScript 只有一種數值類型: number(數字),包括「整數」和帶小數的十進制數。此處「整數」之因此加引號是由於和其餘語言不一樣, JavaScript 沒有真正意義上的整數,這也是它一直以來爲人詬病的地方。這種狀況在未來或許會有所改觀,但目前只有數字類型。 ----《你所不知道的JavaScript(中)》P15
JavaScript 中的「整數」就是沒有小數的十進制數。因此 42.0 即等同於「整數」 42。
JavaScript 中的數字常量通常用十進制表示。例如:
var a = 42; var b = 42.3;
數字前面的 0 能夠省略,
var a = 0.42; var b = .42;
小數點後小數部分最後面的 0 也能夠省略,
var a = 42.0; var b = 42.; //42. 這種寫法沒問題,只是不常見,但從代碼的可讀性考慮,不建議這樣寫。
默認狀況下大部分數字都以十進制顯示,小數部分最後面的 0 被省略,如:
var a = 42.300; var b = 42.0; a; // 42.3 b; // 42
因爲數字值可使用 Number 對象進行封裝,所以數字值能夠調用 Number.prototype 中的方法。例如, tofixed(..) 方法可指定小數部分的顯示位數 :
var a = 42.59; a.toFixed( 0 ); // "43" a.toFixed( 1 ); // "42.6" a.toFixed( 2 ); // "42.59" a.toFixed( 3 ); // "42.590" a.toFixed( 4 ); // "42.5900"
上面的方法不只適用於數字變量,也適用於數字常量。不過對於 . 運算符須要給予特別注意,由於它是一個有效的數字字符,會被優先識別爲數字常量的一部分,而後纔是對象屬性訪問運算符。
// 無效語法: 42.toFixed( 3 ); // SyntaxError // 下面的語法都有效: (42).toFixed( 3 ); // "42.000" 0.42.toFixed( 3 ); // "0.420" 42..toFixed( 3 ); // "42.000 42 .toFixed(3); // "42.000" 注意.運算符前有空格
42.tofixed(3) 是無效語法,由於 . 被視爲常量 42. 的一部分(如前所述),因此沒有 . 屬性訪問運算符來調用 tofixed 方法。
42..tofixed(3) 則沒有問題,由於第一個 . 被視爲 number 的一部分,第二個 . 是屬性訪問運算符。只是這樣看着奇怪,實際狀況中也不多見。在基本類型值上直接調用的方法並不多見,不過這並不表明很差或不對。
0.1 + 0.2 === 0.3; // false
從數學角度來講,上面的條件判斷應該爲 true,可結果倒是 false 。這個問題相信不少人在剛接觸JavaScript的時候或多或少聽過或者見過。緣由是,二進制浮點數中的 0.1 和 0.2 並非十分精確,它們相加的結果並不是恰好等於0.3,而是一個比較接近的數字 0.30000000000000004,因此條件判斷結果爲 false。
那麼應該怎樣來判斷 0.1 + 0.2 和 0.3 是否相等呢?
最多見的方法是設置一個偏差範圍值,一般稱爲「機器精度」(machine epsilon), 對JavaScript 的數字來講,這個值一般是 2^-52 (2.220446049250313e-16)。從 ES6 開始,該值定義在 Number.EPSILON 中,咱們能夠直接拿來用,也能夠爲 ES6 以前的版本寫 polyfill:
if (!Number.EPSILON) { Number.EPSILON = Math.pow(2,-52); }
可使用 Number.EPSILON 來比較兩個數字是否相等(在指定的偏差範圍內):
function numbersCloseEnoughToEqual(n1,n2) { return Math.abs( n1 - n2 ) < Number.EPSILON; } var a = 0.1 + 0.2; var b = 0.3; numbersCloseEnoughToEqual( a, b ); // true numbersCloseEnoughToEqual( 0.0000001, 0.0000002 ); // false
可以呈現的最大浮點數大約是 1.798e+308(這是一個至關大的數字),它定義在 Number.MAX_VALUE 中。最小浮點數定義在 Number.MIN_VALUE 中,大約是 5e-324,它不是負數,但無限接近於 0 !
數字的呈現方式決定了「整數」的安全值範圍遠遠小於 Number.MAX_VALUE。可以被「安全」呈現的最大整數是 2^53 - 1,即 9007199254740991,在 ES6 中被定義爲Number.MAX_SAFE_INTEGER。最小整數是 -9007199254740991,在 ES6 中被定義爲 Number.MIN_SAFE_INTEGER。
Number.isSafeInteger( Number.MAX_SAFE_INTEGER ); // true Number.isSafeInteger( Math.pow( 2, 53 ) ); // false Number.isSafeInteger( Math.pow( 2, 53 ) - 1 ); // true
有時 JavaScript 程序須要處理一些比較大的數字,如數據庫中的 64 位 ID 等。因爲JavaScript 的數字類型沒法精確呈現 64 位數值,因此必須將它們保存(轉換)爲字符串。
JavaScript 數據類型中有幾個特殊的值須要開發人員特別注意和當心使用。
undefined 類型只有一個值,即 undefined。 null 類型也只有一個值,即 null。它們的名稱既是類型也是值。
undefined 和 null 常被用來表示「空的」值或「不是值」的值。兩者之間有一些細微的差異。例如:
• null 指空值(empty value)
• undefined 指沒有值(missing value)
或者:
• undefined 指從未賦值
• null 指曾賦過值,可是目前沒有值
null 是一個特殊關鍵字,不是標識符,咱們不能將其看成變量來使用和賦值。然而undefined 倒是一個標識符,能夠被看成變量來使用和賦值。
在非嚴格模式下,咱們能夠爲全局標識符 undefined 賦值:
function foo() { undefined = 2; // 很是糟糕的作法! } foo(); function foo() { "use strict"; undefined = 2; // TypeError! } foo();
在非嚴格和嚴格兩種模式下,咱們能夠聲明一個名爲 undefined 的局部變量(強烈禁止此作法)。
function foo() { "use strict"; var undefined = 2; console.log( undefined ); // 2 } foo();
注意:永遠不要從新定義 undefined。
void 運算符
undefined 是一個內置標識符(除非被從新定義,見前面的介紹),它的值爲 undefined,經過 void 運算符便可獲得該值。表達式 void ___ 沒有返回值,所以返回結果是 undefined。 void 並不改變表達式的結果,只是讓表達式不返回值:
var a = 42; console.log( void a, a ); // undefined 42
咱們能夠用 void 0 來得到 undefined,固然只用void true 或其餘void 表達式也是能夠的,void 0、 void 1 、void true 和 undefined 之間並無實質上的區別。都是獲得 undefined。
數字類型中有幾個特殊的值,下面將詳細介紹。
若是數學運算的操做數不是數字類型(或者沒法解析爲常規的十進制或十六進制數字),就沒法返回一個有效的數字,這種狀況下返回值爲 NaN。NaN 意指「不是一個數字」(not a number),這個名字容易引發誤會,後面將會提到。將它理解爲「無效數值」「失敗數值」或者「壞數值」可能更準確些。 或者也能夠把NaN理解爲「不是數字的數字」 。
var a = 2 / "foo"; // NaN typeof a === "number"; // true
NaN 是一個「警惕值」(sentinel value,有特殊用途的常規值),用於指出數字類型中的錯誤狀況,即「執行數學運算沒有成功,這是失敗後返回的結果」。
NaN 是一個特殊值,它和自身不相等,是惟一一個非自反的值。即NaN==NaN爲false,而 NaN != NaN 爲 true,很奇怪吧? 那這樣的話咱們該如何比較和肯定某個返回結果是否爲NaN呢?
var a = 2 / "foo"; Number.isNaN(a); // true
實際上還有一個更簡單的方法,即利用 NaN 不等於自身這個特色。 NaN 是 JavaScript 中惟一一個不等於自身的值。 那麼就能夠這樣判斷
isNaN = function(n) { return n !== n; };
var a = 1 / 0;
上例的結果爲 Infinity(即 Number.POSITIVE_INfiNITY)。一樣:
var a = 1 / 0; // Infinity var b = -1 / 0; // -Infinity
如 果 除 法 運 算 中 的 一 個 操 做 數 爲 負 數, 則 結 果 爲 -Infinity( 即 Number.NEGATIVE_INfiNITY)。
和純粹的數學運算不一樣, JavaScript 的運算結果有可能溢出,此時結果爲Infinity 或者 -Infinity。 計算結果一旦溢出爲無窮數(infinity)就沒法再獲得有窮數。換句話說,就是你能夠從有窮走向無窮,但沒法從無窮回到有窮。
有人也許會問:「那麼無窮除以無窮會獲得什麼結果呢?」咱們的第一反應可能會是「1」或者「無窮」,惋惜都不是。由於從數學運算和 JavaScript 語言的角度來講, Infinity/Infinity 是一個未定義操做,結果爲 NaN。
那麼有窮正數除以 Infinity 呢?很簡單,結果是 0。有窮負數除以 Infinity 呢?結果是 -0。
JavaScript 有一個常規的 0(也叫做 +0)和一個 -0。
-0 除了能夠用做常量之外,也能夠是某些數學運算的返回值。例如:
var a = 0 / -3; // -0 var b = 0 * -3; // -0
負零在開發調試控制檯中一般顯示爲 -0,但在一些老版本的瀏覽器中仍然會顯示爲 0。 注意:加法和減法運算不會獲得負零(negative zero)。
根據規範,對負零進行字符串化會返回 "0":
var a = 0 / -3; a; // -0 a.toString(); // "0" a + ""; // "0" String( a ); // "0" // JSON也如此 JSON.stringify( a ); // "0"
有意思的是,若是反過來將其從字符串轉換爲數字,獲得的結果是準確的:
+"-0"; // -0 Number( "-0" ); // -0 JSON.parse( "-0" ); // -0
負零轉換爲字符串的結果使人費解,它的比較操做也是如此:
var a = 0; var b = 0 / -3; a == b; // true -0 == 0; // true a === b; // true -0 === 0; // true 0 > -0; // false a > b; // false
-0===0?那這樣咱們該如何判斷是 0 仍是 -0?能夠試試如下的方法:
function isNegZero(n) { n = Number( n ); return (n === 0) && (1 / n === -Infinity); } isNegZero( -0 ); // true isNegZero( 0 / -3 ); // true isNegZero( 0 ); // false
如前所述, NaN 和 -0 在相等比較時的表現有些特別。因爲 NaN 和自身不相等,因此必須使用 ES6 中的 Number.isNaN(..)。而 -0 等於 0(對於 === 也是如此),所以咱們必須使用 isNegZero(..) 這樣的工具函數。好在ES6 中新加入了一個工具方法 Object.is(..) 來判斷兩個值是否絕對相等,能夠用來處理上述全部的特殊狀況:
var a = 2 / "foo"; var b = -3 * 0; Object.is( a, NaN ); // true Object.is( b, -0 ); // true Object.is( b, 0 ); // false
上面的 Object.is( ) 咱們大體能夠這樣理解
Object.is = function(v1, v2) { // 判斷是不是-0 if (v1 === 0 && v2 === 0) { return 1 / v1 === 1 / v2; } // 判斷是不是NaN if (v1 !== v1) { return v2 !== v2; } // 其餘狀況 return v1 === v2; };
注意:能使用 == 和 === 時就儘可能不要使用 Object.is(..),由於前者效率更高、更爲通用。 Object.is(..) 主要用來處理那些特殊的相等比較。