Number
Number 类型表示我们通常意义上的“数字”。这个数 字大致对应数学中的有理数,当然,在计算机中,我们有一定的精度限制。
JavaScript 中的 Number 类型有 18437736874454810627(即 2^64-2^53+3) 个值。
JavaScript 中的 Number 类型基本符合 IEEE 754-2008 规定的双精度浮点数规则,但是 JavaScript 为了表达几个额外的语言场景 (比如不让除以 0 出错,而引入了无穷大的概 念),规定了几个例外情况:
NaN,占用了 9007199254740990,这原本是符合 IEEE 规则的数字; Infinity,无穷大;
-Infinity,负无穷大。
另外,值得注意的是,JavaScript 中有 +0 和 -0,在加法类运算中它们没有区别,但是除 法的场合则需要特别留意区分,“忘记检测除以 -0,而得到负无穷大”的情况经常会导致 错误,而区分 +0 和 -0 的方式,正是检测 1/x 是 Infinity 还是 -Infinity。
根据双精度浮点数的定义,Number 类型中有效的整数范围是 -0x1fffffffffffff 至 0x1fffffffffffff,所以 Number 无法精确表示此范围外的整数。
同样根据浮点数的定义,非整数的 Number 类型无法用 ==(=== 也不行) 来比较,一 段著名的代码,为什么在 JavaScript 中,0.1+0.2 不能 =0.3:
console.log(0.1 + 0.2 == 0.3);
这里输出的结果是 false,说明两边不相等的,这是浮点运算的特点,也是很多同学疑惑的 来源,浮点数运算的精度问题导致等式左右的结果并不是严格相等,而是相差了个微小的 值。
所以实际上,这里错误的不是结论,而是比较的方法,正确的比较方法是使用 JavaScript 提供的最小精度值:
console.log(Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);
检查等式左右两边差的绝对值是否小于最小精度,才是正确的比较浮点数的方法。这段代码 结果就是 true 了。
Symbol
Symbol 是 ES6 中引入的新类型,它是一切非字符串的对象 key 的集合,在 ES6 规范中,整个对象系统被用 Symbol 重塑。
Symbol 可以具有字符串类型的描述,但是即使描述相同,Symbol 也不相等。
我们创建 Symbol 的方式是使用全局的 Symbol 函数。例如:
var mySymbol = Symbol("my symbol");
一些标准中提到的 Symbol,可以在全局的 Symbol 函数的属性中找到。例如,我们可以 使用 Symbol.iterator 来自定义 for…of 在对象上的行为:
var o = new Object;
o[Symbol.iterator] = function(){
var v = 0;
return{next:function(){return{ value:v++, done: v>10}
}
}
}
for(var v of o)
console.log(v); // 0 1 2 3 ... 9
代码中我们定义了 iterator 之后,用 for(var v of o) 就可以调用这个函数,然后我们可以 根据函数的行为,产生一个 for…of 的行为。
这里我们给对象 o 添加了 Symbol.iterator 属性,并且按照迭代器的要求定义了一个 0 到 10 的迭代器,之后我们就可以在 for of 中愉快地使用这个 o 对象啦。
这些标准中被称为“众所周知”的 Symbol,也构成了语言的一类接口形式。它们允许编写 与语言结合更紧密的 API。
Object
3 与 new Number(3) 是完全不同的值,它们一个是 Number 类 型,一个是对象类型。
Number、String 和 Boolean,三个构造器是两用的,当跟 new 搭配时,它们产生对象,当直接调用时,它们表示强制类型转换。
Symbol 函数比较特殊,直接用 new 调用它会抛出错误,但它仍然是 Symbol 对象的构造 器。
JavaScript 语言设计上试图模糊对象和基本类型之间的关系,我们日常代码可以把对象的 方法在基本类型上使用,比如:
console.log("abc".charAt(0)); //a