1. undefined

为什么有的编程规范要求用 void 0 来代替 undefined?

Undefined 类型表示未定义,它的类型只有一个值,就是 undefined。任何变量在未声明前或者未赋值前都是Undefined 类型,值为 undefined,一般我们可以用全局变量 undefined 来表达这个值。

在 JavaScript 中,undefined 是一个变量名,而不是一个关键字,这是公认的设计失误之一。用 undefined 这个变量来获取 ‘undefined’ 值的时候,现代浏览器里不同环境下的表象是不同的。因为其是变量,因此可以在任意使用的时候对其进行重新赋值,如 undefined=2,但是在全局环境里这种赋值是不会生效的,也就是说对 undefined 赋值后的变量值仍是 undefined,但是在局部环境下是可以的,如:

  1. var undefined;
  2. undefined = 2;
  3. console.log(undefined); // 2
  4. (function(undefined){
  5. console.log(undefined); // foo
  6. })('foo')

为了避免在使用中被篡改,可以使用 void 0 来替换。

Undefined 跟 Null 有一定的表意差别,Null 表示的是:“定义了但是值为空”。所以,在实际编程时,我们一般不会把变量赋值为 undefined,这样可以保证所有值为 undefined 的变量,都是从未赋值的自然状态。

2. null

Null 类型也只有一个值,也就是 null,它的语义表示空值,由于是关键字不可被赋值,因此可以放心使用。

最佳实践最佳实践是:声明一个变量,如果这个变量将作为一个对象使用则赋初始值 {} 或者使用函数设置为 Object.create(null),如果这个变量将要作为字符串使用,则赋初始值 ‘’,如果将要作为数字,则赋初始值 0,当然所有值都可以赋初始值 null ,表示空而不区分类型。这样 undefined 的含义就进一步的明确为 “未声明”。

3. String

String 有最大长度是 2^53 - 1, 这在一般开发中都是够用的, 这个所谓最大长度,是字符串的 UTF16 编码长度,所以,字符串的最大长度,实际上是受字符串的编码长度影响的。

个别方法:

[includes(s, pos)](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/includes)

判断一个字符串里是否包含其他字符串。传入的第一个参数 s 是待查找的子序列,传入的第二个参数是查找开始的索引位置,默认为0可以不传。

由于这是 ECMAScript 6 新增的特性,因此有些老旧的浏览器上是不支持这个 API 的,需要添加 polyfill

  1. // 入口处添加此段代码
  2. if(!String.prototype.includes){
  3. // 如果不存在函数,则添加该函数
  4. String.prototype.includes = function (str, start){
  5. 'use strict';
  6. if(typeof start !== 'number'){
  7. start = 0;
  8. }
  9. if(start + str.length > this.length){
  10. return false;
  11. }else {
  12. return this.indexOf(str, start) > -1;
  13. }
  14. }
  15. }

endsWith(s, this_len)

判断一个字符串是否以给定字符串结尾,结果返回布尔值。传入的第一个参数 s 是待检查的字符串,传入的第二个参数用来指定被检查字符串的长度,默认是被检查字符串的长度可以不传。

注意,传入的第二个参数如果小于原来的被检查字符串长度,则会先对原始字符串截取,如指定了a 长度为10而 a原始长度为20,则 a = a.substring(0, 10)。

由于这是 ECMAScript 6 新增的特性,因此有些老旧的浏览器上是不支持这个 API 的,需要添加 polyfill

  1. if (!String.prototype.endsWith) {
  2. String.prototype.endsWith = function(search, this_len) {
  3. if (this_len === void 0 || this_len > this.length) {
  4. this_len = this.length;
  5. }
  6. return this.substring(this_len - search.length, this_len) === search;
  7. };
  8. }

4. Number

0.1 + 0.2 === 0.3 // false 为什么?
JavaScirpt 使用 Number 类型来表示数字(整数或浮点数),遵循 IEEE 754 标准,通过 64 位来表示一个数字(1 + 11 + 52)

  • 1 符号位,0 表示正数,1 表示负数 s
  • 11 指数位(e)
  • 52 尾数,小数部分(即有效数字)

最大安全数字:Number.MAX_SAFE_INTEGER = Math.pow(2, 53) - 1,转换成整数就是 16 位,所以 0.1 === 0.1,是因为通过 toPrecision(16) 去有效位之后,两者是相等的。
在两数相加时,会先转换成二进制,0.1 和 0.2 转换成二进制的时候尾数会发生无限循环,然后进行对阶运算,JS 引擎对二进制进行截断,所以造成精度丢失。
所以总结:精度丢失可能出现在进制转换和对阶运算中

Number 实例上的方法

  • Number.prototype.toLocaleString([locales [, options]])返回这个数字在特定语言环境下的表示字符串,当数字是整数且不传入其他参数时,转化后的字符串将表现为“逗号符千位分割”。可以通过传入的不同参数指定最终格式化出来的数据结果。最常见的有需求需要将展示数字格式化时可以这么用
    1. (123456.123).toLocaleString('us', {style: "decimal"}) // "123,456.123"
    2. (123456).toLocaleString('us', {style: "currency",currency:'USD' }) // "US$123,456.00"

5. Boolean

  1. !!a = Boolean(a) 强制转换为布尔值

6. BigInt

BigInt 是一个内置对象,它提供了一种方法来表示大于 2- 1 (这原本是 Javascript中可以用 Number 表示的最大数字)的整数。

使用在一个整数字面量后面加 n 的方式定义一个 BigInt ,如:10n,或者调用函数BigInt()

  1. const theBiggestInt = 9007199254740991n;
  2. const alsoHuge = BigInt(9007199254740991);
  3. // ↪ 9007199254740991n
  4. const hugeString = BigInt("9007199254740991");
  5. // ↪ 9007199254740991n
  6. const hugeHex = BigInt("0x1fffffffffffff");
  7. // ↪ 9007199254740991n
  8. const hugeBin = BigInt("0b11111111111111111111111111111111111111111111111111111");
  9. // ↪ 9007199254740991n

它在某些方面类似于 Number ,但是也有几个关键的不同点:不能用于 Math 对象中的方法;不能和任何 Number 实例混合运算,两者必须转换成同一种类型。

在两种类型来回转换时要小心,因为 BigInt 变量在转换成 Number 变量时可能会丢失精度。

使用 typeof 测试时, BigInt 对象返回 “bigint” :

  1. typeof 1n === 'bigint'; // true
  2. typeof BigInt('1') === 'bigint'; // true

使用 Object 包装后, BigInt 被认为是一个普通 “object” :

  1. typeof Object(1n) === 'object'; // true

常见的运算操作都可以用来进行计算,除 >>> (无符号右移)之外的 位操作 也可以支持。因为 BigInt 都是有符号的, >>> (无符号右移)不能用于 BigInt

/ 操作符对于整数的运算也没问题。可是因为这些变量是 BigInt 而不是 BigDecimal ,该操作符结果会向零取整,也就是说不会返回小数部分。

  1. const expected = 4n / 2n;
  2. // ↪ 2n
  3. const rounded = 5n / 2n;
  4. // ↪ 2n, not 2.5n

BigIntNumber 不是严格相等的,但是宽松相等的。

  1. 0n === 0
  2. // ↪ false
  3. 0n == 0
  4. // ↪ true

NumberBigInt 可以进行比较。

  1. 1n < 2
  2. // ↪ true
  3. 2n > 1
  4. // ↪ true
  5. 2 > 2
  6. // ↪ false
  7. 2n > 2
  8. // ↪ false
  9. 2n >= 2
  10. // ↪ true

两者也可以混在一个数组内并排序。

  1. const mixed = [4n, 6, -12n, 10, 4, 0, 0n];
  2. // ↪ [4n, 6, -12n, 10, 4, 0, 0n]
  3. mixed.sort();
  4. // ↪ [-12n, 0, 0n, 10, 4n, 4, 6]

BigInt 在需要转换成 Boolean 的时表现跟 Number 一致。

  1. BigInt 类型只用来表示整数,没有小数位
  2. BigInt 可以用来表示任意大小的数字
  3. BigInt 的基本表现形式与 Number 相同,只是不能使用 Math 提供的方法,>>> 无符号右移位运算也不可以
  4. BigInt 可以用来跟普通类型的数字之间进行大小判断但是不能进行运算,两者不是同一种类型
  5. BigInt 往普通数字转化的时候如果超出了上限则会丢失精度

参考资料: BigInt — MDN

7. Symbol

  1. 1. 独一无二的属性值
  2. 2. 可以作为私有属性,不可以被遍历到(除了 Object.getOwnPropertySymbols)
  3. const obj = {
  4. [Symbol('a')]: 1,
  5. [Symbol('a')]: 2,
  6. }

8. Object

Array 一些静态方法

[Array.from()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)

Array.from() 静态方法从类数组或可迭代对象中创建一个新的浅复制数组实例(es6新增)。

  1. console.log(Array.from('foo'));
  2. // expected output: Array ["f", "o", "o"]
  3. console.log(Array.from([1, 2, 3], x => x + x));
  4. // expected output: Array [2, 4, 6]

函数的语法定义是:

  1. Array.from(arrayLike [, mapFn [, thisArg]])

也可以这么理解: Array.from(obj, mapFn, thisArg) —> Array.from(obj).map(mapFn, thisArg)

[Array.isArray()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)

判断对象是不是数组,如果是返回 true, 如果不是返回 false。函数的语法定义是:

  1. Array.isArray(value)

此Api的实现借助了 toString,在不支持该 Api 的浏览器上可以使用如下 polyfill

  1. if (!Array.isArray) {
  2. Array.isArray = function(arg) {
  3. return Object.prototype.toString.call(arg) === '[object Array]';
  4. };
  5. }

在与 instanceof 相比时,更倾向于使用 isArray

[Array.of()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/of)

创建参数数目可变的新数组实例,无论参数的数目或类型如何。
代码实现:

  1. if (!Array.of) {
  2. Array.of = function() {
  3. let vals = [];
  4. for(let prop in arguments){
  5. vals.push(arguments[prop]);
  6. }
  7. return vals;
  8. }
  9. }

typeof

js 类型与类型转换 - 图1