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

一、數組

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

 

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

相關文章
相關標籤/搜索