js值----你所不知道的JavaScript系列(6)


1、數組

在 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 屬性。

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]

 

這里有個問題需要特別注意,如果字符串鍵值能夠被強制類型轉換為十進制數字的話,它就會被當作數字索引來處理。

var a = [ ];
a["13"] = 13;
a.length; // 14

 

 

2、字符串

字符串和數組的確很相似,都有 length 屬性以及 indexOf(..)(從 ES5開始數組支持此方法)和 concat(..) 方法: 

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"

 

 

3、數字

JavaScript 只有一種數值類型: number(數字),包括“整數”和帶小數的十進制數。此處“整數”之所以加引號是因為和其他語言不同, JavaScript 沒有真正意義上的整數,這也是它一直以來為人詬病的地方。這種情況在將來或許會有所改觀,但目前只有數字類型。  ----《你所不知道的JavaScript(中)》P15

JavaScript 中的“整數”就是沒有小數的十進制數。所以 42.0 即等同於“整數” 42。

 

3.1 數字的語法

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 的一部分,第二個 . 是屬性訪問運算符。只是這樣看着奇怪,實際情況中也很少見。在基本類型值上直接調用的方法並不多見,不過這並不代表不好不對。 

 

3.2 較小的數值

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 ! 

 

3.3 整數的安全范圍

數字的呈現方式決定了“整數”的安全值范圍遠遠小於 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 位數值,所以必須將它們保存(轉換)為字符串。 

3.4 特殊數值

JavaScript 數據類型中有幾個特殊的值需要開發人員特別注意和小心使用。

 

3.4.1 不是值的值

undefined 類型只有一個值,即 undefined。 null 類型也只有一個值,即 null。它們的名稱既是類型也是值。

undefined 和 null 常被用來表示“空的”值或“不是值”的值。二者之間有一些細微的差別。例如:

• null 指空值(empty value)
• undefined 指沒有值(missing value)
或者:
• undefined 指從未賦值
• null 指曾賦過值,但是目前沒有值

null 是一個特殊關鍵字,不是標識符,我們不能將其當作變量來使用和賦值。然而undefined 卻是一個標識符,可以被當作變量來使用和賦值。 

 

3.4.2 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 0void 1 、void true undefined 之間並沒有實質上的區別。都是得到 undefined。

 

3.5 特殊的數字

數字類型中有幾個特殊的值,下面將詳細介紹。

 

3.5.1 不是數字的數字

如果數學運算的操作數不是數字類型(或者無法解析為常規的十進制或十六進制數字),就無法返回一個有效的數字,這種情況下返回值為 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;
};

 

3.5.2 無窮數

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。 

3.6 零值

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

 

3.7 特殊等式

如前所述, 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(..) 主要用來處理那些特殊的相等比較。 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM