Array.prototype.flat() / flatMap()
# Array.prototype.flat() / flatMap()flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。flatMap()与 map() 方法和深度为1的 flat() 几乎相同.,不过它会首先使用映射函数映射每个元素,然后将结果压缩成一个新数组,这样效率会更高。例子如下:var arr1 = [1, 2, 3, 4]arr1.map(x => [x * 2]) // [[2], [4], [6], [8]]arr1.flatMap(x => [x * 2]) // [2, 4, 6, 8]// 深度为1arr1.flatMap(x => [[x * 2]]) // [[2], [4], [6], [8]]flatMap()可以代替reduce() 与 concat(),例子如下:var arr = [1, 2, 3, 4]arr.flatMap(x => [x, x * 2]) // [1, 2, 2, 4, 3, 6, 4, 8]// 等价于arr.reduce((acc, x) => acc.concat([x, x * 2]), []) // [1, 2, 2, 4, 3, 6, 4, 8]但这是非常低效的,在每次迭代中,它创建一个必须被垃圾收集的新临时数组,并且它将元素从当前的累加器数组复制到一个新的数组中,而不是将新的元素添加到现有的数组中。
String.prototype.trimStart() / trimLeft() / trimEnd() / trimRight()
# String.prototype.trimStart() / trimLeft() / trimEnd() / trimRight()在ES5中,我们可以通过trim()来去掉字符首尾的空格,但是却无法只去掉单边的,但是在ES10之后,我们可以实现这个功能。如果我们要去掉开头的空格,可以使用trimStart()或者它的别名trimLeft(),同样的,如果我们要去掉结尾的空格,我们可以使用trimEnd()或者它的别名trimRight()。例子如下:const Str = ' Hello world! 'console.log(Str) // ' Hello world! 'console.log(Str.trimStart()) // 'Hello world! 'console.log(Str.trimLeft()) // 'Hello world! 'console.log(Str.trimEnd()) // ' Hello world!'console.log(Str.trimRight()) // ' Hello world!'不过这里有一点要注意的是,trimStart()跟trimEnd()才是标准方法,trimLeft()跟trimRight()只是别名。在某些引擎里(例如Chrome),有以下的等式:String.prototype.trimLeft.name === "trimStart"String.prototype.trimRight.name === "trimEnd"
Object.fromEntries()
# Object.fromEntries()Object.fromEntries() 方法把键值对列表转换为一个对象,它是Object.entries()的反函数。例子如下:const entries = new Map([ ['foo', 'bar'], ['baz', 42]])const obj = Object.fromEntries(entries)console.log(obj) // Object { foo: "bar", baz: 42 }
Symbol.prototype.description
# Symbol.prototype.descriptiondescription 是一个只读属性,它会返回Symbol对象的可选描述的字符串。与 Symbol.prototype.toString() 不同的是它不会包含Symbol()的字符串。例子如下:Symbol('desc').toString(); // "Symbol(desc)"Symbol('desc').description; // "desc"Symbol('').description; // ""Symbol().description; // undefined// 具名 symbolsSymbol.iterator.toString(); // "Symbol(Symbol.iterator)"Symbol.iterator.description; // "Symbol.iterator"//全局 symbolsSymbol.for('foo').toString(); // "Symbol(foo)"Symbol.for('foo').description; // "foo"
String.prototype.matchAll
# String.prototype.matchAllmatchAll() 方法返回一个包含所有匹配正则表达式的结果及分组捕获组的迭代器。并且返回一个不可重启的迭代器。例子如下:var regexp = /t(e)(st(\d?))/gvar str = 'test1test2'str.match(regexp) // ['test1', 'test2']str.matchAll(regexp) // RegExpStringIterator {}[...str.matchAll(regexp)] // [['test1', 'e', 'st1', '1', index: 0, input: 'test1test2', l
Function.prototype.toString() 返回注释与空格
# Function.prototype.toString() 返回注释与空格在以往的版本中,Function.prototype.toString()得到的字符串是去掉空白符号的,但是从ES10开始会保留这些空格,如果是原生函数则返回你控制台看到的效果,例子如下:function sum(a, b) { return a + b;}console.log(sum.toString())// "function sum(a, b) {// return a + b;// }"console.log(Math.abs.toString()) // "function abs() { [native code] }"
try-catch
# 在以往的版本中,try-catch里catch后面必须带异常参数,例如:// ES10之前try {// tryCode} catch (err) {// catchCode}但是在ES10之后,这个参数却不是必须的,如果用不到,我们可以不用传,例如:try { console.log('Foobar')} catch { console.error('Bar')}
BigInt
# BigIntBigInt 是一种内置对象,它提供了一种方法来表示大于 253 - 1 的整数。这原本是 Javascript中可以用 Number 表示的最大数字。BigInt 可以表示任意大的整数。可以用在一个整数字面量后面加 n 的方式定义一个 BigInt ,如:10n,或者调用函数BigInt()。在以往的版本中,我们有以下的弊端:// 大于2的53次方的整数,无法保持精度2 ** 53 === (2 ** 53 + 1)// 超过2的1024次方的数值,无法表示2 ** 1024 // Infinity但是在ES10引入BigInt之后,这个问题便得到了解决。以下操作符可以和 BigInt 一起使用: +、*、-、**、% 。除 >>> (无符号右移)之外的位操作也可以支持。因为 BigInt 都是有符号的, >>> (无符号右移)不能用于 BigInt。BigInt 不支持单目 (+) 运算符。/ 操作符对于整数的运算也没问题。可是因为这些变量是 BigInt 而不是 BigDecimal ,该操作符结果会向零取整,也就是说不会返回小数部分。BigInt 和 Number不是严格相等的,但是宽松相等的。所以在BigInt出来以后,JS的原始类型便增加到了7个,如下:•Boolean•Null•Undefined•Number•String•Symbol (ES6)•BigInt (ES10)
globalThis
# globalThisglobalThis属性包含类似于全局对象 this值。所以在全局环境下,我们有:globalThis === this // true
import()
# import()静态的import 语句用于导入由另一个模块导出的绑定。无论是否声明了 严格模式,导入的模块都运行在严格模式下。在浏览器中,import 语句只能在声明了 type="module" 的 script 的标签中使用。但是在ES10之后,我们有动态 import(),它不需要依赖 type="module" 的script标签。所以我们有以下例子:const main = document.querySelector("main")for (const link of document.querySelectorAll("nav > a")) { link.addEventListener("click", e => { e.preventDefault() import('/modules/my-module.js') .then(module => { module.loadPageInto(main); }) .catch(err => { main.textContent = err.message; }) })}
私有元素与方法
# 在ES10之前,如果我们要实现一个简单的计数器组件,我们可能会这么写:// web component 写法class Counter extends HTMLElement { get x() { return this.xValue } set x(value) { this.xValue = value window.requestAnimationFrame(this.render.bind(this)) } clicked() { this.x++ } constructor() { super() this.onclick = this.clicked.bind(this) this.xValue = 0 } connectedCallback() { this.render() } render() { this.textContent = this.x.toString() }}window.customElements.define('num-counter', Counter)但是在ES10之后我们可以使用私有变量进行组件封装,如下:class Counter extends HTMLElement { #xValue = 0 get #x() { return #xValue } set #x(value) { this.#xValue = value window.requestAnimationFrame(this.#render.bind(this)) } #clicked() { this.#x++ } constructor() { super(); this.onclick = this.#clicked.bind(this) } connectedCallback() { this.#render() } #render() { this.textContent = this.#x.toString() }}window.customElements.define('num-counter', Counter)