以上就是给各位分享一文搞懂JavaScript新数据类型BigInt,其中也会对js新的数据类型进行解释,同时本文还将给你拓展BigInt来自C#中的Javascript等价物、javascript/
以上就是给各位分享一文搞懂 JavaScript 新数据类型 BigInt,其中也会对js新的数据类型进行解释,同时本文还将给你拓展BigInt 来自 C# 中的 Javascript 等价物、javascript / js数据类型,数据类型转换、JavaScript 中的BigInt类型、Javascript 提案 BigInt 的一些坑等相关知识,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
本文目录一览:- 一文搞懂 JavaScript 新数据类型 BigInt(js新的数据类型)
- BigInt 来自 C# 中的 Javascript 等价物
- javascript / js数据类型,数据类型转换
- JavaScript 中的BigInt类型
- Javascript 提案 BigInt 的一些坑
一文搞懂 JavaScript 新数据类型 BigInt(js新的数据类型)
BigInt
数据类型是为了让JavaScript程序能表示超出Number
类型支持的数值范围。在对大整数进行数学运算时,以任意精度表示整数的能力尤为重要。有了BigInt
,整数溢出将不再是一个问题。
此外,你可以安全地使用高精度时间戳、大整数 ID 等,而不必使用任何变通方法。BigInt
目前处于 stage 3 提案阶段。一旦加入到规范中,它将成为JavaScript中的第二种数字数据类型,这将使支持的数据类型总数达到8个:
Boolean
Null
Undefined
Number
BigInt
String
Symbol
Object
在本文中,我们将仔细研究BigInt
,并了解它如何帮助克服JavaScript中Number
类型的限制。
问题
对于来自其他语言的程序员来说,JavaScript中缺乏显式整数类型常常令人困惑。许多编程语言支持多种数字类型,如float、double、integer和bignum,但JavaScript不是这样。在JavaScript中,所有数字都以双精度64位浮点格式表示,这是由IEEE 754-2008标准定义的。
在此标准下,无法精确表示的非常大的整数将自动四舍五入。准确地说,JavaScript中的Number
类型只能安全地表示 -9007199254740991 (-(253-1))和 9007199254740991 (253-1)之间的整数。任何超出此范围的整数值都可能丢失精度。
这个很容易验证,执行以下代码:
console.log(9999999999999999); // → 10000000000000000
该整数大于JavaScript可以用 Number
原始类型表示的最大数字。因此,它被舍入了。意外的舍入可能会损害程序的可靠性和安全性。这是另一个例子:
// 注意最后一位
9007199254740992 === 9007199254740993; // → true
JavaScript提供了Number.MAX_SAFE_INTEGER
常量,允许你在JavaScript中快速获得最大安全整数。类似地,你可以通过使用Number.MIN_SAFE_INTEGER
常量获得最小安全整数:
const minInt = Number.MIN_SAFE_INTEGER;
console.log(minInt); // → -9007199254740991
console.log(minInt - 5); // → -9007199254740996
// 注意它是如何输出与上面相同的值的
console.log(minInt - 4); // → -9007199254740996
解决办法
为了解决这些限制,一些JavaScript开发人员使用String
类型表示大整数。例如,Twitter API在使用JSON响应时向对象添加了一个id的字符串版本。此外,还开发了一些库,如bignumber.js,以便更容易地处理大整数。
有了 BigInt
,应用程序不再需要一个变通方法或库来安全地表示Number.MAX_SAFE_INTEGER
和Number.Min_SAFE_INTEGER
之外的整数。现在可以在标准JavaScript中执行对大整数的算术操作,而不会有丢失精度的风险。在第三方库上使用原生数据类型的好处是更好的运行时性能。
要创建BigInt
,只需将n
附加到整数的末尾。对比一下:
console.log(9007199254740995n); // → 9007199254740995n
console.log(9007199254740995); // → 9007199254740996
或者,你可以调用BigInt()
构造函数:
BigInt("9007199254740995"); // → 9007199254740995n
BigInt
字面量也可以写成二进制、八进制或十六进制形式:
// 二进制
console.log(0b100000000000000000000000000000000000000000000000000011n);
// → 9007199254740995n
// 十六进制
console.log(0x20000000000003n);
// → 9007199254740995n
// 八进制
console.log(0o400000000000000003n);
// → 9007199254740995n
//注意,不支持旧式八进制语法
console.log(0400000000000000003n);
// → SyntaxError
记住,不能使用严格的相等运算符来比较BigInt
和普通数字,因为它们不是同一类型的:
console.log(10n === 10); // → false
console.log(typeof 10n); // → bigint
console.log(typeof 10); // → number
相反,你可以使用相等运算符,它在处理操作数之前执行隐式类型转换:
console.log(10n == 10); // → true
所有算术运算符都可以在BigInt
上使用,除了一元加号(+
)运算符:
10n + 20n; // → 30n
10n - 20n; // → -10n
+10n; // → TypeError: Cannot convert a BigInt value to a number
-10n; // → -10n
10n * 20n; // → 200n
20n / 10n; // → 2n
23n % 10n; // → 3n
10n ** 3n; // → 1000n
let x = 10n;
++x; // → 11n
--x; // → 10n
不支持一元加号(+
)运算符的原因是,有些程序可能依赖于这样的结果:+
总是产生Number
类型的值,或者抛出异常。改变+
的行为也会破坏asm.js代码。
当然,当与BigInt
操作数一起使用时,算术运算符应该返回一个BigInt
值。因此,除法(/
)运算符的结果会自动四舍五入到最接近的整数。例如:
25 / 10; // → 2.5
25n / 10n; // → 2n
隐式类型转换
因为隐式类型转换可能丢失信息,所以不允许BigInt
和Number
之间的混合操作。当混合使用大整数和浮点数时,结果值可能无法用BigInt
或Number
准确表示。看看下面的例子:
(9007199254740992n + 1n) + 0.5
这个表达式的结果在BigInt
和Number
的范围之外。带有小数部分的Number
不能准确地转换为BigInt
。大于253的BigInt
不能准确转换为Number
。
由于这个限制,不能使用Number
和 BigInt
操作数的组合来执行算术运算。你也不能将 BigInt
传递给Web API和期望Number
类型参数的内置JavaScript函数。试图这样做会导致TypeError
:
10 + 10n; // → TypeError
Math.max(2n, 4n, 6n); // → TypeError
注意,关系运算符不遵循此规则,如下例所示:
10n > 5; // → true
如果希望使用BigInt
和 Number
执行算术计算,首先需要确定应该在哪个域中执行操作。为此,只需通过调用Number()
或BigInt()
来转换操作数:
BigInt(10) + 10n; // → 20n
// or
10 + Number(10n); // → 20
当遇到Boolean
上下文时,BigInt
被视为类似于Number
。换句话说,只要不是0n
, BigInt
就被认为是一个布尔真值:
if (5n) {
// 这个代码块将被执行
}
if (0n) {
// 但这个不会
}
对BigInt
和 Number
进行排序时,不会发生隐式类型转换:
const arr = [3n, 4, 2, 1n, 0, -1n];
arr.sort(); // → [-1n, 0, 1n, 2, 3n, 4]
按位运算符如|
, &
, <<
, >>
和 ^
操作 BigInt
与Number
类似。负数被解释为无穷长二进制补码。不允许混合操作数。以下是一些例子:
90 | 115; // → 123
90n | 115n; // → 123n
90n | 115; // → TypeError
BigInt 构造函数
与其他基本类型一样,可以使用构造函数创建BigInt
。如果可能,传递给BigInt
的参数会自动转换为BigInt
:
BigInt("10"); // → 10n
BigInt(10); // → 10n
BigInt(true); // → 1n
无法转换的数据类型和值会抛出异常:
BigInt(10.2); // → RangeError
BigInt(null); // → TypeError
BigInt("abc"); // → SyntaxError
你可以直接对通过BigInt
构造函数创建的变量执行算术运算:
BigInt(10) * 10n; // → 100n
当用作严格相等运算符的操作数时,使用构造函数创建的BigInt
操作数与常规操作数类似:
BigInt(true) === 1n; // → true
库函数
JavaScript提供了两个库函数来把BigInt
值表示为有符号或无符号整数:
BigInt.asUintN(width, BigInt)
: 包装一个介于 0 和 2width-1之间的BigInt
BigInt.asIntN(width, BigInt)
: 包装一个介于 -2width-1 和2width-1-1之间的BigInt
这些函数在执行64位算术操作时特别有用。这样你就可以保持在预定的范围内。
浏览器支持及转换
在撰写本文时,Chrome +67和Opera +54完全支持BigInt
数据类型。不幸的是,Edge和Safari还没有实现它。火狐默认不支持BigInt
,但可以通过在about:config
中将javascript.options.bigint
设置为true
来启用。支持的浏览器的最新列表可以在Can I use…上找到。
不幸的是,转换BigInt
是一个极其复杂的过程,这会导致严重的运行时性能损失。也不可能直接填充BigInt
,因为该提议改变了几个现有操作符的行为。目前,更好的选择是使用JSBI库,它是BigInt
建议的纯JavaScript 实现。
这个库提供了一个与内置BigInt
行为完全相同的API。下面是使用JSBI的方法:
import JSBI from ''./jsbi.mjs'';
const b1 = JSBI.BigInt(Number.MAX_SAFE_INTEGER);
const b2 = JSBI.BigInt(''10'');
const result = JSBI.add(b1, b2);
console.log(String(result)); // → ''9007199254741001''
使用JSBI的一个优点是,一旦浏览器支持得到改进,你就不需要重写代码了。相反,您可以使用babel plugin将你的JSBI代码自动编译成本地的BigInt
代码。此外,JSBI的性能与内置的BigInt
实现相当。你可以期待更广泛的浏览器支持BigInt
。
结论
BigInt
是一种新的数据类型,用于当整数值大于Number
数据类型支持的范围时。这种数据类型允许我们安全地对大整数执行算术操作,表示高精度时间戳,使用大整数 ID 等等,而不需要使用库。
重要的是要记住,不能使用Number
和BigInt
操作数的组合来执行算术运算。你需要通过显式转换操作数来确定操作应该在哪个域中执行。此外,出于兼容性的原因,不允许在BigInt
上使用一元加号(+
)操作符。
你觉得怎么样?你觉得BigInt
有用吗?欢迎评论!
往期文章:
这15个Vue自定义指令,让你的项目开发爽到爆
不可不知的JavaScript 变量 Temporal Dead Zone
顺手点“在看”,每天早下班;转发加关注,共奔小康路~
本文分享自微信公众号 - 1024译站(trans1024)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
BigInt 来自 C# 中的 Javascript 等价物
如何解决BigInt 来自 C# 中的 Javascript 等价物?
我用 Javascript 编写了一个脚本,将字符串转换为 BigInt:
BigInt("0x40000000061c924300441104148028c80861190a0ca4088c144020c60c831088")
结果为:28948022309972676171332135370609260321582865398090858033119816311589805691016
我需要找到与此函数等效的 C#。我试过了:
Convert.ToInt64("0x40000000061c924300441104148028c80861190a0ca4088c144020c60c831088")
和 BigInteger.Parse("0x40000000061c924300441104148028c80861190a0ca4088c144020c60c831088",NumberStyles.Any)
但两者都抛出异常:无法解析该值。
有没有人知道什么函数可以从字符串中获取结果,比如 JS 中的 BigInt()?
解决方法
它应该使用 ToString() 转换回字符串格式 方法,您需要在“R”的ToString中传递参数 告诉它输出 BigInteger 作为它自己。
这是来自文档:
"在大多数情况下,ToString 方法支持 50 位十进制数的精度。也就是说,如果 BigInteger 值超过 50 位,则输出字符串中仅保留 50 位最高有效位;所有其他数字替换为零。但是,BigInteger 支持“R”标准格式说明符,它用于往返数值。由 ToString(String) 方法返回的带有“R”格式字符串的字符串保留了整个 BigInteger 值,然后可以使用 Parse 或 TryParse 方法解析以恢复其原始值,而不会丢失任何数据。”
您可能想尝试使用“R”而不是“N”。
查看更多信息和示例:
http://msdn.microsoft.com/en-us/library/dd268260.aspx
,您需要删除前导“0x”才能解析十六进制。
private static BigInteger? ParseBigInteger(string input) {
if (input.StartsWith("0x",StringComparison.OrdinalIgnoreCase)) {
if (BigInteger.TryParse(input.Substring(2),NumberStyles.AllowHexSpecifier,CultureInfo.InvariantCulture,out var bigInt)) {
return bigInt;
}
}
else if (BigInteger.TryParse(input,NumberStyles.Any,out var bigInt)) {
return bigInt;
}
return null;
}
//invocation
var bigInt = ParseBigInteger("0x40000000061c924300441104148028c80861190a0ca4088c144020c60c831088");
// => result: 28948022309972676171332135370609260321582865398090858033119816311589805691016
,
对应long(或Int64),64位整数
参考:https://www.educative.io/edpresso/what-is-a-bigint-in-javascript
,您需要从字符串中删除 ''x'' 字符并允许使用十六进制说明符,然后它就会起作用:
BigInteger.Parse("0x40000000061c924300441104148028c80861190a0ca4088c144020c60c831088".Replace("x",string.Empty),NumberSpecifiers.AllowHex
javascript / js数据类型,数据类型转换
1)基本类型
---数字,采用IEEE754标准定义的64位浮点格式.
特殊数值常量:
Infinity 无穷大的特殊值
NaN 非数字值
Number.MAX_VALUE 可表示的最大数字
Number.MIN_VALUE 可表示的最小数字
Number.NaN 非数字值
Number.POSITIVE_INFINITY 正无穷大
Number.NEGATIVE_INFINITY 负无穷大
把数字转为字符串6种方式
var n = 1.23456;
var n_as_str = n+"";
String(n);
n.toString(x); //x=2,binary; x=8, octonay; x=16,hexadecimal.if empty,decimal
n.toFixed(x); //小数点后位数
n.toExponential(x); //显示指数形式,x表示小数位
n.toPrecision(x); //若n位数>x时显示为指数,x表示数字的精度
---字符串
字符串转为数字
在数字环境,自动转换为数字,
var num = "2" * "3"; //num = 6
var num = str_val - 0;
var num = Number(str_val); //以10为基数的数字有效,允许开头和结尾的空白
parseInt(str)
parseInt(str,radix) //the same with java
parseFloat(str)
---布尔
显式转换的方法
var x_as_boolean = Boolean(x);
var x_as_boolean = !!x;
---null
表示"无值".
对象转换:布尔环境式时,非空对象为false;字符串环境时"null";数字环境时0;
---undefined
使用未声明的变量时,或使用声明但没有赋值的变量时,或使用不存在的对象属性时,返回
undefined.
对象转换:布尔环境式时,非空对象为false;字符串环境时"undefined";数字环境时NaN;
与null区别:
null是关键字,undefined不是.(ECMAScript v3定义了undefined的全局变量,初始值是undefined)
2)复合类型
对象:已命名的数据的集合
对象直接量:由一个列表构成.列表的表式形式,{key:value,*};(key=标识符/字符串,value=常量/表达式)
对象转换:布尔环境式时,非空对象为true;字符串环境时,toString();数字环境时,valueOf();
数组
不直持多维数组,数组元素可以是数组;
数组元素不必据有相同的类型
3)特殊对象
函数
一般语法,function func_name(args) {func_body;}
lambda函数,function(args){func_body;}
构造函数,new Function("args","func_body");
*说明
计划以后在note目录下发布些整理的笔记,好记心不如烂笔头.主要为了方便自己查找,若读者看了觉得哪儿理解不对,请指教.
这篇是关于javascript的数据类型,主要内容来自"javascript权威指南".
原文链接: http://www.cnblogs.com/hnyei/archive/2012/03/06/2382033.html
JavaScript 中的BigInt类型
Number 的安全范围
和别的强类型编程语言(比如说 C,Java)不同,JavaScript 不区分整数值和浮点数值。
我们可以发现10 === 10.0 // true
。那是因为 JavaScript 的数字类型是基于 IEEE 754 标准中的"双精度"格式,也就是 64 位二进制来实现的,它是通过如下格式来存储数据。
符号位(Sign bit): 1 bit(0 表示正数, 1 表示负数)
指数位(Exponent): 11 bits
有效数字(Significand precision): 53 bits (52 explicitly stored)在二进制中,计算机内部保存有效数字时,第一个有效数字必定是1
,因此这个1
并不会存储。所以52
位有效数字可以存储53
位。
这里可以提到的的一点是:二进制浮点数最大的问题就是在处理0.1 + 0.2
的时候,实际上的结果不是0.3
,而是一个比较接近的数字0.30000000000000004
,这也是因为在它计算的时候,会先转化为二进制,再进行计算导致的偏差。因为我们在用 JavaScript 或者其他遵循 IEEE 754 规范的语言处理带有效数的数字时要特别注意。
JavaScript 的数字格式也就决定了 JavaScript 能够安全表示的整数范围是 -2^53+1 ~ 2^53-1
。
这里我们可以先明确一下“安全”的概念:
- 可以准确地表示为一个 IEEE-754 双精度数字
- 其 IEEE-754 表示不能是舍入任何其他整数以适应 IEEE-754 表示的结果
比如说:比如,2^53 - 1
是一个安全整数,它能被精确表示,在任何 IEEE-754 舍入模式(rounding mode)下,没有其他整数舍入结果为该整数。作为对比,2^53
就不是一个安全整数,它能够使用 IEEE-754 表示,但是2^53 + 1
不能使用 IEEE-754 直接表示,在就近舍入(round-to-nearest)和向零舍入中,会被舍入为2^53
。
可以参考Number.isSafeInteger()的定义。
BigInt 类型
在 ES2020 之前,JavaScript 只有一种数值类型:number(数字),而之后为了安全表达比 -9007199254740991 ~ 9007199254740991
安全范围之外的数字。引入了BigInt
类型。
一般计算机是将整数存储在 CPU 的寄存器中(现在通常是 32 位或 64 位宽, JS 是 64bit),或者存储在寄存器大小的内存块中,这就会带来安全范围的问题。而 BigInt 类型为了保证精度。它是在内存中分配一个对象。我们让它足够大,以一系列块的形式容纳所有 BigInt 的位,我们称之为“数字”
https://v8.dev/blog/bigint
如何使用
- 直接在数字后面加一个
n
- 调用
BigInt()
构造函数
const bigInt = 9007199254740992n; //通过直接在数字后面加n
const bigNumber = BigInt(9007199254740992); // 对十进制数字使用BigInt函数
const bigString = BigInt("9007199254740992"); //对String类型的使用BigInt函数,先隐式转换为十进制的数字,再显式转换为BigIn类型
const bigHex = BigInt(0x20000000000000); // 对十六进制数字使用BigInt函数
const bigBin = BigInt(0b100000000000000000000000000000000000000000000000000000); //对二进制数字使用BigInt函数
以上这些运算生成的值都是9007199254740992n
;
BigInt类型运算
可用操作符
BigInt 中可以运用如下操作符:
符号 | 名称 |
---|---|
+ | 加法 |
* | 乘法 |
- | 减法 |
% | 求余 |
** | 求幂 |
<< | 左移位 |
>> | 右移位 |
- 当 BigInt 使用
/
操作符时,带小数的运算会被取整。
const expected = 4n / 2n; //2n
const rounded = 5n / 2n; //2n, not 2.5n
- 因为 BigInt 都是有符号的,
>>>
(无符号右移)不能用于 BigInt
运算注意事项
BigInt 类型虽然和 Number 很像,可以做各种数学运算,但是在运算过程中要注意两点:
- BigInt 类型不能用 Math 对象中的方法。
- 不能和 Number 示例混合运算。因为 JavaScript 在处理不同类型的运算时,会把他们先转换为同一类型,而 BigInt 类型变量在被隐式转换为 Number 类型时,可能会丢失精度,或者直接报错。
const number = 1;
const bigInt = 9007199254740993n;
number + bigInt; // TypeError: Cannot mix BigInt and other types
BigInt类型和其他类型比较
BigInt 类型的比较和 JavaScript 中的其他类型比较一样,分为宽松相等和严格相等。
const bigInt = 2n;
const int = 2;
const string = "2";
bigInt == int; // true
bigInt == string; // true
bigInt === int; // false
bigInt === string; //false
Javascript 提案 BigInt 的一些坑
昨天译了一篇文章:BigInt:JavaScript 中的任意精度整数。昨晚又抽空总结了一下 BigInt
的那些坑。
1. 定义形式
BigInt
使用数字字面量加 n
表示支持二进制、八进制、十六进制形式。
对于八进制,只支持新写法 0o064n
,不支持旧的写法 0640
。
普通写法:
1n
十六进制:
0x6n
0X6n
八进制:
0o6n
0O6n
06n // ❌SyntaxError
二进制:
0b10n
0B10n
BigInt
不支持科学计数法形式:
1e25n // ❌ SyntaxError
2. 转换为字符串
当作为 key 时,所有值都会被转换为字符串,而 BigInt
转字符串时是没有后缀 n
的。
String(12n) === "12"
因此:
let obj = { };
obj[32n] = 1;
obj[32] === 1;
数组同理, array[5n]
等同于 array[5]
等同于 array["5"]
。
注:这并不意味着 array[xxxn]
和 array[xxx]
是一样的。因为 BigInt
可以超越 Number
的安全表示边界。
let obj = {};
obj[9007199254740993n] = "foo";
obj[9007199254740993n] === "foo"; // ✅
obj["9007199254740993"] === "foo"; // ✅
obj[9007199254740993] === "foo"; // ❌
我们可以通过如下代码查一下原因:
let obj = {};
obj[9007199254740993n] = "foo";
obj[9007199254740993] = "bar";
Object.keys(obj);
// ["9007199254740993", "9007199254740992"]
因为 String(9007199254740993)==="9007199254740992"
。
3. 零值处理
因为 BigInt
表示的是整数,所以只存在一个 0
(无正零和负零之分)。
Object.is(-0, 0) === false
Object.is(-0n, 0n) === true
注意: BigInt
中没有 +0n
,具体原因见上。
4. 等值判断
BigInt
同值判定规则:
数组:
[0].includes(0n) === false
[0n].includes(0n) === true
[0n].includes(+0) === false
[0n].includes(-0) === false
Set
:
new Set([0]).has(0) === true
new Set([0n]).has(0) === false
new Set([0n]).has(0n) === true
new Set([0]).has(0n) === false
Map
:
new Map([[0n, 42]]).has(0n) === true
new Map([[0n, 42]]).has(0) === false
new Map([[0, 42]]).has(0) === true
new Map([[0, 42]]).has(0n) === false
由于 0
和 0n
不相等,所以在集合中,两者可以共存:
let s = new Set([0, 0n]);
s.size === 2;
let m = new Map([[0, 42], [0n, 24]]);
m.size === 2;
5. 与 Number 比较
BigInt
和 Nubmer
的不同。
BigInt
只有函数,没有构造器,因此不能使用 new
来创建 BigInt
的实例。
new Number(0); // ✅
new BigInt(0); // ❌
对某些特殊值的处理不同:
当没有参数时,
Number
返回0
,BigInt
抛出TypeError
Number() // 0
BigInt() // ❌ TypeError
当非数字时,
Number
返回NaN
,BigInt
抛出TypeError
或SyntaxError
Number(undefined) // NaN
BigInt(undefined) // ❌ TypeError
Number(null) // 0
BigInt(null) // ❌ TypeError
Number({}) // NaN
BigInt({}) // ❌ SyntaxError
Number("foo") // NaN
BigInt("foo") // ❌ SyntaxError
两者对于
-0
(负零)的处理也不同
Number(-0) === -0
BigInt(-0) === 0n
两者都会把
true
转换为1
,把false
转换为0
Number(true) === 1n
Number(false) === 0n
BigInt(true) === 1n
BigInt(false) === 0n
对于浮点数,
BigInt
抛出RangeError
异常
BigInt(4.00000001) // ❌ RangeError
对于
NaN
和正负无穷,BigInt
抛出RangeError
异常
BigInt(NaN) // ❌ RangeError
BigInt(-Infinity) // ❌ RangeError
BigInt(+Infinity) // ❌ RangeError
6. 类型转换
BigInt
不能隐式转换为 Number
,所以在接受 Number
作为参数的运算中,将抛出 TypeError
异常
isNaN(0n) // ❌TypeError
isFinite(0n) // ❌TypeError
Math.abs(-4n) // ❌TypeError
"bar".substr(1n) // ❌TypeError
但是 Number
下面的函数可以使用:
Number.isSafeInteger(0n) === false
Number.isFinite(0n) === false
Number.isNaN(0n) === false
Number.parseInt(0n) === 0
7. 继续阅读
BigInt:JavaScript 中的任意精度整数
ES2018 新特征之:异步迭代器 for-await-of
现代编程语言最有趣的 10 大特性
从一个 JSON.parse 错误深入研究 JavaScript 的转义字符