在 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(..) 主要用来处理那些特殊的相等比较。