关于类型,有哪些细节需要注意
# 关于类型,有哪些细节需要注意
- 为什么有的编程规范要求用 void 0 代替 undefined?
- 字符串有最大长度吗?
- 0.1 + 0.2 不是等于 0.3 么?为什么 JavaScript 里不是这样的?
- ES6 新加入的 Symbol 是个什么东西?
- 为什么给对象添加的方法能用在基本类型上?
# 为什么有的编程规范要求用 void 0 代替 undefined?
因为在JavaScript中undefined
并不是保留字段,因此undefined可能会作为变量名进行赋值,从而污染数据。
const undefined = 'nothing'
// 此时给其他变量赋值undefined将会出现数据污染
let tempNumber = undefined // nothing,不是想要的结果
let tempNumber = void 0 // tempNumber = undefined,这才是想要的结果
2
3
4
# 字符串有最大长度吗?
String有最大长度是2^53 - 1,但是这个最大长度,并不是字符数。
因为 String 的意义并非“字符串”,而是字符串的 UTF16 编码,我们字符串的操作 charAt、charCodeAt、length 等方法针对的都是 UTF16 编码。所以,字符串的最大长度,实际上是受字符串的编码长度影响的。
Note:现行的字符集国际标准,字符是以 Unicode 的方式表示的,每一个 Unicode 的码点表示一个字符,理论上,Unicode 的范围是无限的。UTF 是 Unicode 的编码方式,规定了码点在计算机中的表示方法,常见的有 UTF16 和 UTF8。 Unicode 的码点通常用 U+??? 来表示,其中 ??? 是十六进制的码点值。 0-65536(U+0000 - U+FFFF)的码点被称为基本字符区域(BMP)。
# 0.1 + 0.2 不是等于 0.3 么?为什么 JavaScript 里不是这样的?
在JavaScript中的数字类型使用双精度,在其他语言中是double类型。Number类型有18437736874454810627(即 2^64-2^53+3) 个值。
为了表达几个额外的语言场景(比如不让除以0出错,而引入了无穷大的概念),规定了几个额外情况:
- NaN,占用了 9007199254740990,这原本是符合 IEEE 规则的数字;
- Infinity,无穷大;
- -Infinity,负无穷大。
另外,值得注意的是,JavaScript 中有 +0 和 -0,在加法类运算中它们没有区别,但是除法的场合则需要特别留意区分,“忘记检测除以 -0,而得到负无穷大”的情况经常会导致错误,而区分 +0 和 -0 的方式,正是检测 1/x 是 Infinity 还是 -Infinity。
根据双精度浮点数的定义,Number 类型中有效的整数范围是 -0x1fffffffffffff 至 0x1fffffffffffff,所以 Number 无法精确表示此范围外的整数。
非整数的 Number 类型无法用 ==
(===
也不行) 来比较:
console.log( 0.1 + 0.2 == 0.3); // false
这里输出的结果是 false,说明两边不相等的,这是浮点运算的特点,浮点数运算的精度问题导致等式左右的结果并不是严格相等,而是相差了个微小的值。
所以实际上,这里错误的不是结论,而是比较的方法,正确的比较方法是使用 JavaScript 提供的最小精度值:
console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);
Math.abs(x)
:获取x的绝对值
Number.EPSILON
: 表示 1 与Number可表示的大于 1 的最小的浮点数之间的差值。
# ES6 新加入的 Symbol 是个什么东西?
Symbol 是 ES6 中引入的新类型,它是一切非字符串的对象 key 的集合,在 ES6 规范中,整个对象系统被用 Symbol 重塑。
Symbol 可以具有字符串类型的描述,但是即使描述相同,Symbol 也不相等。
var mySymbol = Symbol("my symbol"); // 创建
# 为什么给对象添加的方法能用在基本类型上?
JavaScript 中的几个基本类型,都在对象类型中有一个“亲戚”。它们是:
- Number;
- String;
- Boolean;
- Symbol;
3 和 new Number(3) 是完全不同的值:
- 3是Number类型
- new Number(3)是对象类型
Number、String和Boolean,三个构造器是两用的,当跟new搭配时,他们产生对象,当直接调用时,他们标识强制类型转换。
Symbol 函数比较特殊,直接用 new 调用它会抛出错误,但它仍然是 Symbol 对象的构造器。
JavaScript 语言设计上试图模糊对象和基本类型之间的关系,我们日常代码可以把对象的方法在基本类型上使用,比如:
console.log("abc".charAt(0)); //a
甚至我们在原型上添加方法,都可以应用于基本类型,比如以下代码,在 Symbol 原型上添加了 hello 方法,在任何 Symbol 类型变量都可以调用。
Symbol.prototype.hello = () => console.log("hello");
var a = Symbol("a");
console.log(typeof a); //symbol,a 并非对象
a.hello(); //hello,有效
2
3
4
5
答:.
运算符提供了装箱操作,它会根据基础类型构造一个临时对象,使得我们能在基础类型上调用对应对象的方法。