前言
在前面的学习中我们已经了解到,JavaScript 里的引用值类型都最终继承自 Object,而除了 Object,JavaScript 还提供了非常多的内置对象,这些内置对象极大地丰富了 JavaScript 的内容,为其提供了非常丰富且强大的能力。本文将介绍一些常用的内置对象,以及他们的特性。了解所有的 JavaScript 内置对象可查阅文档 MDN JavaScript 内置对象。
1. 包装对象
1.1 Boolean
Boolean 是 boolean 字面量的对象包装器,它有两个作用:
- 直接调用
Boolean(source),将值转为boolean字面量 - 作为构造函数调用,创建
Boolean对象
const a = 1;
const b = Boolean(a);
console.log("b =", b); // b = true
const c = new Boolean(a);
console.log("c =", c); // c = Boolean { true }
console.log("typeof c:", typeof c); // typeof c: object
从上面的结果可以看出来,Boolean 包装对象和字面量值的使用和含义是不同的:
- 布尔值字面量的值类型为
boolean Boolean包装对象的值类型为object
所以 Boolean 这个函数通常只会把它用来将其他类型的值转为 boolean 类型的值,也就是直接调用它,而不是把它作为构造函数来使用。
一般来说,我们在开发中不会使用
Boolean来将目标值转为boolean类型,通过!!这样两次执行 逻辑非 操作,可以更快捷地将目标值转为boolean类型也就是说:
Boolean(source)等价于!!source
1.2 Number
Number 是 number 字面量的对象包装器,它有三个作用:
- 提供一系列内置的静态数值/静态操作方法
- 直接执行
Number(source),将值转为数字 - 作为构造函数,创建
Number对象
Number 对象提供的属性和方法见文档 MDN Number。
文档的左侧列出了 Number 提供的静态属性、静态方法,以及实例方法,这些实例方法是所有 Number 对象实例和 number 类型字面量都可以使用的。
和 Boolean 对象一样,将 Number 作为构造函数使用时,最终得到的结果并不是一个数字,而是一个对象。
const a = "123";
const b = Number(a)
console.log("b =", b); // b = 123
const c = new Number(a);
console.log("c =", c); // c = Number {123}
console.log("typeof c:", typeof c); // typeof c: object
将一个值转换为数字字面量时,有三种方式:
- 直接使用
Number() - 使用
Number.parseInt() - 使用
Number.parseFloat()
Number()
转换规则:
null、undefined转换为0true转换为1,false转换为0- 空字符串
""转换为0 - 形如
整数部分.小数部分的字符串,可以不包含小数点和小数部分,此时直接转换为对应的数值表示 - 其他的所有值都转换为
NaN
还有一种将其他值转为数字的方法:直接使用一元运算符
+。它的转换规则和使用Number()的规则是一样的,只是简洁一点。
Number.parseInt()
Number.parseInt() 用于将字符串转换为十进制数字 (非字符串的值会先被强制转化为字符串),也可用于数字整数部分的进制转换。
- 转换规则:
Number.parseInt()从第一个非空白字符开始,直到遇到非数字字符为止 (与进制有关) ,将这个连续的字符串片段转换为对应的数字表示。 - 注意:
0x这个开头会被视为十六进制前导,不会被计入检测到的数字中。
console.log(Number.parseInt("0x10")); // "0x10" 被视为十六进制的值,转换成十进制后输出:16
第二个参数 radix 对判定规则的影响
- 如果进制为
2,则 2~9 也会被视为非数字 - 如果进制是
11,则 a/A 也会被视为数字 - 如果进制是
36,则 a-z/A-Z 都会被视为数字
总结:一个数字、英文字符是否被视为数字,与指定的进制有关,进制的值为 2~36,有可能被视为数字的字符有 0~9 的数字和 a-z/A-Z 英文字母。
console.log(Number.parseInt("0x10", 16)); // 此时进制可以写也可以不写,都会以十六进制输出 16
console.log(Number.parseInt("0b1")); // 默认十进制,输出的结果为第一个数字 0
console.log(Number.parseInt("0b1", 16)); // 此时指定十六进制,输出的结果为十六进制转十进制的值 177
console.log(Number.parseInt("z")); // 默认十进制,z 不能被解析为数字,输出结果 NaN
console.log(Number.parseInt("z", 36)); // 指定三十六进制,z 被解析为数字,输出三十六进制转十进制结果 35
如果
Number.parseInt()的参数是数字,那么它会把这个数字按照 去尾法 转换为整数。
Number.parseFloat()
Number.parseFloat() 用于将字符串 (非字符串的值会先被强制转化为字符串) 转换为浮点数。
- 转换规则:
Number.parseFloat():从第一个非空白字符开始,遇到的第一个.被视为小数点,然后继续,直到遇到非数字字符为止,将这个连续的字符串片段转换为对应的数字表示。 - 注意:
Number.parseFloat()只有一个参数,只能转换为十进制的浮点数。
console.log(Number.parsInt("233.3.3n")); // 233
console.log(Number.parsFloat("233.3.3n")); // 233
console.log(Number.parsInt("n233.3.3")); // NaN
console.log(Number.parsFloat("n233.3.3")); // NaN
console.log(Number.parsInt(233.6)); // 233
console.log(Number.parsFloat(233.6)); // 233.6
1.3 String
String 是 string 字面量的对象包装器,它有三个作用:
- 提供一系列字符串的静态操作方法
- 直接执行
String(source),将值转为字符串 - 作为构造函数,创建
String对象
字符串在日常开发中用得很多,ES6 之后增加了 模板字符串,为字符串提供了更丰富的功能,尤其是在字符串拼接方面。
字符串只有一个 length 属性,这个属性指的是字符串里代码单元的数量,有的字符被编码成一个代码单元,有的字符被编码成两个代码单元。
console.log("a".length); // 1
console.log("安".length); // 1
console.log("🍔".length); // 2。这个符号可以通过 `Win + ;` 两个按键调出来,仅限 Windows 平台
大部分的中文是编码一个代码单元,少部分的生僻字会被编码成两个代码单元。
目前,String 总共有三个静态方法,这些静态方法在一般的日常开发中使用很少,感兴趣的话可以查阅文档 MDN String 静态方法。
最常用的是 String 的实例方法,这些方法包括裁剪字符串、拼接字符串、替换指定的字符、查找指定的字符等,这些方法无需硬背,只需要在使用的时候去翻阅 MDN String 实例方法 的文档就可以了。这些方法大多数有自己的特性,建议使用的时候多查阅,用多了、看多了就记住了。
2 Symbol
把 Symbol 单独列出来,虽然 symbol 是一种基础类型,但 Symbol() 并不能像 Boolean、Number、String 那样作为构造函数来使用。
Symbol() 用来产生一个 symbol 类型的值,它返回的值都是唯一的,即使给这个函数调用传入相同的参数:
const s1 = Symbol(1);
const s2 = Symbol(1);
console.log("s1 等于 s2?", s1 == s2); // s1 等于 s2? false
console.log("s1 完全等于 s2?", s1 === s2); // s1 完全等于 s2? false
Symbol 主要是提供了一些静态属性和静态方法,实例的属性和方法只有继承自 Object 的那几个。
为什么要有
Symbol?为的是给遵循 ECMAScript 规范的编程语言提供 元编程 的能力。
Symbol 有几个关键的静态属性:
Symbol.iterator:定义对象的迭代器接口,这个迭代器接口可用于for...of循环。Symbol.hasInstance:定义判断某对象是否为某构造器的实例的方法,这个方法会被用于instanceof操作符。Symbol.toPrimitive:定义接受首选类型并返回对象原始值的表示的方法,这个方法会被用于强制类型转换。
翻阅 Symbol 的文档就会发现,它提供的这些能力大部分都是为了底层封装的,比如自己的 SDK、自己定义的数据结构等等。所以如果只是做普通的业务开发,一般来说不会接触到这个数据类型,只需要了解上面这三个比较关键的静态属性的含义即可。
3. 一般对象
3.1 BigInt
BigInt 是用来将值转换成 bigint 这个类型的,并提供了一些静态的属性和方法。
注意:
BigInt不可以作为构造函数调用!new BigInt(source)会报语法错误。
bigint 这个数据类型是在 ES2020 才正式引入 ECMAScript 规范的,所以兼容性相对来说没有那么好,具体的可以查看文档 MDN BigInt 浏览器兼容性。
BigInt 的使用场景有限,因为一般的日常业务开发中不会使用到它,只有在特别巨大的数值场景下,才会使用到。
目前我所能想到的场景就是,从文件里以字符串的格式读取到数据,或者从后端以字符串的格式传递过来数据,然后在前端利用 BigInt 将对应的值转为 bigint 类型的值进行各种计算。此时就需要 BigInt 能将字符串转为 bigint 类型的值,所以 BigInt() 本身就是可以做这件事的。
BigInt 的实例只有继承自 Object 的几个方法,没有额外的实例方法。BigInt 本身也只提供了 asIntN 和 asUintN 两个静态方法,用于将 BigInt 的值转换为特定范围内的整数。
3.2 Math
Math 这个内置对象只有静态属性和静态方法。
Math 的静态属性是数学中的一些常量,比如自然对数的底数 e 对应的是 Math.E,圆周率的 π 对应的是 Math.PI。
Math 的静态方法是数学计算中的一些常见运算,比如 取绝对值 运算对应的是 Math.abs(),四舍五入 运算对应的是 Math.round(),以及所有的三角函数运算,Math 里都有。
Math 的静态方法 Math.random() 是用来随机产生一个 0~1之间的小数的,基于这个方法,我们可以实现下面这样的一个工具函数,用于生成指定范围内的数字。
/**
* @description 随机生成指定范围内的数字
* @param { number } min 范围的最小值
* @param { number } max 范围的最大值
* @param { number } precision 保留的小数位数,仅支持自然数
* @returns { number }
*/
export function sizedRandom(min, max, precision = 0) {
try {
// 先检查参数的合法性
checkArgs();
} catch (error) {
// 存在不合法时,打印出对应的错误信息
console.error(error);
// 然后直接返回
return;
}
return genResult();
// 这个函数才是核心
function genResult() {
// 首先产生一个随机数
const value = Math.random();
// 然后确定结果的缩放倍数
const rate = max - min;
// 再对结果进行缩放
const scaledValue = value * rate;
// 再对结果保留小数
const roundedValue = +scaledValue.toFixed(precision);
// 最后加上最小值,得到结果
const result = roundedValue + min;
return result;
}
function checkArgs() {
const types = [typeof min, typeof max, typeof precision];
const argNames = ["min", "max", "precision"];
const acceptTypes = ["number", "number", "number"];
for (let index = 0; index < types.length; index++) {
const type = types[index];
const acceptType = acceptTypes[index];
if (type !== acceptType) {
throw new Error(`参数 ${argNames[index]} 仅允许为 "${acceptType}" 类型!`);
}
}
if (precision < 0 || Math.round(precision) !== precision) {
throw new Error("精度仅支持自然数!当前的精度为:", precision);
}
if (min > max) {
throw new Error("最小值超过了最大值!", { min, max });
}
}
}
上面这段代码也许你会觉得复杂,但这样的工具函数才有足够的健壮性。
之前的学习过程中听过一句话:“在 JavaScript 开发中,永远不要相信用户的输入。” 我理解这句话时,“用户” 既指 “使用系统的人”,也指使用产出代码的 “开发者”。
使用 Math.random() 也可以实现随机产生一个布尔值。
/**
* @description 随机产生一个布尔值
* @returns { boolean }
*/
export function randomBoolean() {
return Math.random() > 0.5;
}
3.3 Date
Date 用于处理时间日期。
Date 支持任意合法格式的日期字符串作为入参,如果不传入参,则默认创建当前时刻的日期对象。
Date 实例没有属性,只有方法,且 Date 本身提供了几个静态方法,用于获取时间日期或操作实例对象。
在日常开发中,我用得较多的是静态方法 Date.now(),这个静态方法直接返回当前时刻的时间戳。
实际项目中,原生 Date 一般使用的较少,使用第三方库的较多,目前比较流行的两个日期处理库是 moment.js (中文文档) 和 dayjs (中文文档)。
总结
本文介绍了 JavaScript 的一些基础内置对象,我简单地将其分为了 “包装对象” 和 “一般对象” 两类,包括 Boolean、Number、String、Symbol、BigInt、Math 和 Date。此外,还有其他的很多内置对象,如错误对象 Error、数组对象 Array等。有的对象不那么常用,有的将在后续的文章中深入讲解。
本文如有描述错误的地方,欢迎指正~