此文初衷如下几点:
- 源于为了理解不同阶段浏览器对不有些办法的反对状况,不便疾速定位不同浏览器下的兼容问题;
- 同时做为文档查阅,能更分明的理解每一阶段的新个性;
- 帮忙大家面试加分,试问熟知每个阶段的更新细节总归会给面试官好印象;
以此与大家共勉,有帮忙的话棘手给个赞,谢谢~~
ES11 新个性(2020 公布)
ECMAScript 语言标准的第 11 版本。
String.prototype.matchAll(regexp)
matchAll
办法返回一个蕴含所有匹配正则表达式的后果及分组捕捉组的迭代器。入参:
regexp
为正则表达式对象。如果所传参数不是一个正则表达式对象,则会隐式地应用new RegExp(obj)
将其转换为一个RegExp
。返回:一个迭代器(不可重用,后果耗尽须要再次调用办法,获取一个新的迭代器)。
- 根本应用
const regexp = /t(e)(st(\d?))/g;
const str = "test1test2";
// 返回迭代器
const iterator = str.matchAll(regexp);
const array = [...iterator];
console.log(array[0]);
// expected output: Array ["test1", "e", "st1", "1"]
console.log(array[1]);
// expected output: Array ["test2", "e", "st2", "2"]
- 控制台执行
-
注意事项:
matchAll
入参regexp
必须跟上g
按全文查找,否则会抛出TypeError
异样/i
:疏忽大小写/g
:全文查找呈现的所有匹配字符/m
:多行查找/ig
:全文查找、疏忽大小写
- 兼容性
Dynamic import 动静引入
规范用法的
import
导入的模块是动态的,会使所有被导入的模块,在加载时就被编译(无奈做到按需编译,升高首页加载速度)。有些场景中,你可能心愿依据条件导入模块或者按需导入模块,这时你能够应用动静导入代替动态导入。上面的是你可能会须要动静导入的场景:
-
应用场景
- 当动态导入的模块很显著的升高了代码的加载速度且被应用的可能性很低,或者并不需要马上应用它。
- 当动态导入的模块很显著的占用了大量零碎内存且被应用的可能性很低。
- 当被导入的模块,在加载时并不存在,须要异步获取
- 当导入模块的说明符,须要动静构建。(动态导入只能应用动态说明符)
- 当被导入的模块有副作用(这里说的副作用,能够了解为模块中会间接运行的代码),这些副作用只有在触发了某些条件才被须要时。(原则上来说,模块不能有副作用,然而很多时候,你无法控制你所依赖的模块的内容)
- 惯例用作异步按需加载
function callback() {
// 同样反对 await 写法
import("moduleB")
.then((module) => {// todo})
.catch((err) => {// load error});
}
- 兼容性
import.meta
import.meta
是一个给 JavaScript 模块裸露特定上下文的元数据属性的对象。它蕴含了这个模块的信息,比如说这个模块的 URL。
-
根本应用
- 通过
script
标签援用
<script type="module" src="my-module.mjs"></script>; // 在 my-module.mjs 中应用 console.log(import.meta); // {url: "file:///home/user/my-module.mjs"}
- 通过
import
援用
// a.js import "b.js?param1=test"; // b.js import.meta.url; // ...b.js?param1=test
- 通过
- 兼容性
export * as alias from namespace
模块重定向
- 根本应用
// 如果咱们想要在以后模块中,导出指定导入模块的默认导出(等于是创立了一个“重定向”):// module "redirect-module.js"
export {default} from './other-module';
export * from './other-module';
export * as otherName from './other-module';
- 兼容性
Promise.allSettled(iterable)
入参:一个可迭代的对象,其中每个成员都是
Promise
返回:一个在所有给定的
promise
都曾经fulfilled
或rejected
后的promise
,并带有一个对象数组,每个对象示意对应的promise
后果。当您有多个彼此不依赖的异步工作胜利实现时,或者您总是想晓得每个
promise
的后果时,通常应用它。相比之下,
Promise.all()
更适宜彼此相互依赖或者在其中任何一个reject
时立刻完结。
- 根本应用
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) =>
setTimeout(reject, 100, "foo")
);
const promises = [promise1, promise2];
Promise.allSettled(promises).then((results) =>
results.forEach((result) => console.log(result.status))
);
// Promise {<pending>}
// fulfilled
// rejected
- 兼容性
BigInt
最新的 ECMAScript 规范定义了 8 种数据类型:7 中原始类型:Boolean、Null、Undefined、Number、BigInt、String、Symbol;和 Object;
BigInt
类型是 JavaScript 中的一个根底的数值类型,能够用任意精度示意整数。应用 BigInt,您能够平安地存储和操作大整数,甚至能够超过数字的平安整数限度。BigInt 是一种内置对象,它提供了一种办法来示意大于
2^53 - 1
的整数。这本来是 Javascript 中能够用Number
示意的最大数字。BigInt 能够示意任意大的整数。
BigInt
是通过在整数开端附加n
或调用构造函数来创立的。通过应用常量
Number.MAX_SAFE_INTEGER
(2^53 – 1),您能够取得能够用数字递增的最平安的值。通过引入 BigInt,您能够操作超过Number.MAX_SAFE_INTEGER
的数字。能够对
BigInt
应用运算符+、
`、-、
*和
%`,就像对数字一样。BigInt 严格来说并不等于一个数字,但它是涣散的。
- 根本应用
const x = 2n ** 53n;
// ↪ 9007199254740992n
const y = x + 1n;
// ↪ 9007199254740993n
const previousMaxSafe = BigInt(Number.MAX_SAFE_INTEGER);
// ↪ 9007199254740991n
const maxPlusOne = previousMaxSafe + 1n;
// ↪ 9007199254740992n
const theFuture = previousMaxSafe + 2n;
// ↪ 9007199254740993n, this works now!
const multi = previousMaxSafe * 2n;
// ↪ 18014398509481982n
const subtr = multi – 10n;
// ↪ 18014398509481972n
const mod = multi % 10n;
// ↪ 2n
const bigN = 2n ** 54n;
// ↪ 18014398509481984n
bigN * -1n
// ↪ –18014398509481984n
- 在将
BigInt
转换为Boolean
时,它的行为相似于一个数字:if、
`||、&&、
Boolean 和`!。
0n === 0;
// ↪ false
0n == 0;
// ↪ true
BigInt
不能与数字调换操作。否则,将抛出TypeError
。
1 + 1n; // Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
- 当应用
BigInt
时,带小数的运算会被取整。
const expected = 4n / 2n;
// ↪ 2n
const rounded = 5n / 2n;
// ↪ 2n, not 2.5n
- Number 和 BigInt 能够进行比拟
1n == 1;
// ↪ true
1n === 1;
// ↪ false
1n < 2;
// ↪ true
2n > 1;
// ↪ true
2 > 2;
// ↪ false
2n > 2;
// ↪ false
2n >= 2;
// ↪ true
// 两者也能够混在一起进行比拟
const mixed = [4n, 6, -12n, 10, 4, 0, 0n];
// ↪ [4n, 6, -12n, 10, 4, 0, 0n]
mixed.sort();
// ↪ [-12n, 0, 0n, 10, 4n, 4, 6]
// 留神被 Object 包装的 BigInts 应用 object 的比拟规定进行比拟,只用同一个对象在比拟时才会相等。0n === Object(0n); // false
Object(0n) === Object(0n); // false
0n === 0n; // true
const o = Object(0n);
o === o; // true
- 兼容性
globalThis
全局属性
globalThis
蕴含全局的this
值,相似于全局对象(global object)。
-
之前不同环境下
web
中:能够通过window
、self
或者frames
取到全局对象Web Workers
中:只有self
能够Node.js
中:必须应用global
- 在涣散模式下,能够通过
this
来获取全局对象 - 在严格模式下,
this
会返回undefined
,能够通过function(){return this}
-
globalThis
提供了一个规范的形式来获取不同环境下的全局this
对象(全局对象本身)不像
window
或者self
这些属性,它确保能够在有无窗口的各种环境下失常工作。所以,你能够安心的应用globalThis
,不用放心它的运行环境。为便于记忆,你只须要记住,全局作用域中的this
就是globalThis
。 -
HTML 与 WindowProxy
在很多引擎中,
globalThis
被认为是实在的全局对象的援用,然而在浏览器中,因为 iframe 以及跨窗口安全性的思考,它理论援用的是实在全局对象(不能够被间接拜访)的Proxy
代理。在通常的利用中,很少会波及到代理与对象自身的区别,然而也须要加以留神。 - 根本应用
// 没有 globalThis 之前获取全局对象的对立形式
var getGlobal = function () {if (typeof self !== "undefined") {return self;}
if (typeof window !== "undefined") {return window;}
if (typeof global !== "undefined") {return global;}
throw new Error("unable to locate global object");
};
var globals = getGlobal();
if (typeof globals.setTimeout !== "function") {// 此环境中没有 setTimeout 办法!}
// 有了 globalThis 之后,只需
if (typeof globalThis.setTimeout !== "function") {// 此环境中没有 setTimeout 办法!}
- 兼容性
Optional chaining (?.)
可选链 操作符 (
?.
) 容许读取位于连贯对象链深处的属性的值,而不用明确验证链中的每个援用是否无效。?.
操作符的性能相似于.
链式操作符,不同之处在于,在援用为空(null
或者undefined
) 的状况下不会引起谬误,该表达式短路返回值是undefined
。与函数调用一起应用时,如果给定的函数不存在,则返回
undefined
。
- 语法
obj?.prop // 对象属性
obj?.[expr] // 对象表达式
arr?.[index] // 数组索引
func?.(args) // 办法调用
- 根本应用
const adventurer = {
name: 'Alice',
cat: {name: 'Dinah'}
};
// 不存在的属性
const dogName = adventurer.dog?.name;
console.log(dogName);
// expected output: undefined
// 不存在的函数
console.log(adventurer.someNonExistentMethod?.());
// expected output: undefined
- 以往比拟应用
// 不必 ?.
let nestedProp = obj.first && obj.first.second;
// 应用 ?.
// 通过应用 ?. 操作符取代 . 操作符,JavaScript 会在尝试拜访 obj.first.second 之前,// 1. 先隐式地查看并确定 obj.first 既不是 null 也不是 undefined。// 2. 如果 obj.first 是 null 或者 undefined,表达式将会短路计算间接返回 undefined。let nestedProp = obj.first?.second;
// 等价于
let temp = obj.first;
let nestedProp = ((temp === null || temp === undefined) ? undefined : temp.second);
- 与函数调用
留神: 如果存在一个属性名且不是函数, 应用 ?. 依然会产生一个 TypeError 异样 (x.y is not a function).
// 当应用一个 API 的办法可能不可用时
// 函数调用时如果被调用的办法不存在,应用可选链能够使表达式主动返回 undefined 而不是抛出一个异样。let result = someInterface.customMethod?.();
// 旧写法
if (onError) { // 校验 onError 是否真的存在
onError(err.message);
}
// 新写法
onError?.(err.message); // 如果 onError 是 undefined 也不会有异样
- 与表达式
let nestedProp = obj?.['prop' + 'Name'];
- 不能用于赋值
let object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment
- 拜访数组元素
let arrayItem = arr?.[42];
- 兼容性
Nullish coalescing operator (??)
空值合并操作符(
??
)是一个逻辑操作符,当左侧的操作数为null
或者undefined
时,返回其右侧操作数,否则返回左侧操作数。与逻辑或操作符(
||
)不同,逻辑或操作符会在左侧操作数为假值时返回右侧操作数。也就是说,如果应用||
来为某些变量设置默认值,可能会遇到意料之外的行为。比方为假值(例如,''
或0
)时。见上面的例子。
- 根本应用
const nullValue = null;
const emptyText = ""; // 空字符串,是一个假值,Boolean("") === false
const someNumber = 42;
const valA = nullValue ?? "valA 的默认值";
const valB = emptyText ?? "valB 的默认值";
const valC = someNumber ?? 0;
console.log(valA); // "valA 的默认值"
console.log(valB); // ""(空字符串尽管是假值,但不是 null 或者 undefined)console.log(valC); // 42
- 与
||
比照
因为 || 是一个布尔逻辑运算符,左侧的操作数会被强制转换成布尔值用于求值。任何假值(0,”,NaN,null,undefined)都不会被返回。这导致如果你应用 0,” 或 NaN 作为有效值,就会呈现不可意料的结果。
let myText = ''; // An empty string (which is also a falsy value)
let notFalsyText = myText || 'Hello world';
console.log(notFalsyText); // Hello world
let preservingFalsy = myText ?? 'Hi neighborhood';
console.log(preservingFalsy); // '' (as myText is neither undefined nor null)
- 短路
与 OR 和 AND 逻辑操作符类似,当左表达式不为
null
或undefined
时,不会对右表达式进行求值。
function A() { console.log('函数 A 被调用了'); return undefined; }
function B() { console.log('函数 B 被调用了'); return false; }
function C() { console.log('函数 C 被调用了'); return "foo"; }
console.log(A() ?? C());
// 顺次打印 "函数 A 被调用了"、"函数 C 被调用了"、"foo"
// A() 返回了 undefined,所以操作符两边的表达式都被执行了
console.log(B() ?? C());
// 顺次打印 "函数 B 被调用了"、"false"
// B() 返回了 false(既不是 null 也不是 undefined)// 所以右侧表达式没有被执行
- 不能与
||
和&&
共用
null || undefined ?? "foo"; // 抛出 SyntaxError
true || undefined ?? "foo"; // 抛出 SyntaxError
// 然而,如果应用括号来显式表明运算优先级,是没有问题的:(null || undefined) ?? "foo"; // 返回 "foo"
- 应用
?.
操作符
let customer = {
name: "Carl",
details: {age: 82}
};
let customerCity = customer?.city ?? "暗之城";
console.log(customerCity); //“暗之城”
- 兼容性
ES10 新个性(2019 公布)
Optional catch
binding(catch 绑定可选)
容许在不应用
catch
绑定的状况下省略绑定,catch
的参数能够疏忽
- 根本应用
// 以往
try {} catch (error) {
}
// 当初反对语法,catch 能够不应用抛出的 error
try {// ...} catch {// ...}
- 兼容性
JSON superset(json 超集)
ECMAScript 宣称 JSON 是的子集
JSON.parse
,但(据充沛记录)这是不正确的,因为 JSON 字符串能够蕴含未本义的 U + 2028 LINE SEPARATOR 和 U + 2029 PARAGRAPH SEPARATOR 字符,而 ECMAScript 字符串则不能。JSON 语法由 ECMA-404 定义,并由 RFC 7159 永恒固定,然而 ECMA-262 的 DoubleStringCharacter 和SingleStringCharacter生产能够扩大为容许不本义的 U + 2028 LINE SEPARATOR 和 U + 2029 PARAGRAPH SEPARATOR 字符。
在 ES2019 之前,它会产生谬误
SyntaxError: Invalid or unexpected token
const PS = eval("'\u2029'");
- 兼容性
Symbol.prototype.description
description
是一个只读属性,它会返回Symbol
对象的可选形容的字符串。对象能够通过一个可选的形容创立,可用于调试,但不能用于拜访 symbol 自身。
Symbol.prototype.description
属性能够用于读取该形容。与
Symbol.prototype.toString()
不同的是它不会蕴含 “Symbol()
” 的字符串。具体请看实例。
- 根本应用
Symbol('desc').toString(); // "Symbol(desc)"
Symbol('desc').description; // "desc"
Symbol('').description; //""
Symbol().description; // undefined
// well-known symbols
Symbol.iterator.toString(); // "Symbol(Symbol.iterator)"
Symbol.iterator.description; // "Symbol.iterator"
// global symbols
Symbol.for('foo').toString(); // "Symbol(foo)"
Symbol.for('foo').description; // "foo"
- 兼容性
Function.prototype.toString
修改
返回一个示意以后函数源代码的字符串,修改了返回函数中蕴含正文(箭头函数除外)
function sum /* comments... */(a, b) {return a + b;}
console.log(sum.toString());
// es2019 之前
// function sum (a, b) {
// return a + b;
// }
// eS2019 之后
// function sum /* comments... */(a, b) {
// return a + b;
// }
// native code 并不凋谢
console.log(Math.abs.toString());
// function abs() { [native code] }
// 箭头函数不会蕴含正文
const arrowFunction /* comment */ = /* comment */ () => {};
console.log(arrowFunction.toString()); // () => {}
Object.fromEntries
Object.fromEntries(iterable)
办法接管一个键值对的列表参数,并返回一个带有这些键值对的 新对象。参数:
iterable
相似Array
、Map
或者其它实现了可迭代协定的可迭代对象。返回:一个由该迭代对象条目提供对应属性的新对象。
- 根本应用
// Map to Object
const map = new Map([['foo', 'bar'], ['baz', 42] ]);
const obj = Object.fromEntries(map);
console.log(obj); // {foo: "bar", baz: 42}
// Array to Object
const arr = [['0', 'a'], ['1', 'b'], ['2', 'c'] ];
const obj = Object.fromEntries(arr);
console.log(obj); // {0: "a", 1: "b", 2: "c"}
Object.fromEntries
是与Object.entries()
相同的办法
const object1 = {a: 1, b: 2, c: 3};
const object2 = Object.fromEntries(Object.entries(object1)
.map(([key, val]) => [key, val * 2])
);
console.log(object2);
// {a: 2, b: 4, c: 6}
- 兼容性
Well-formed JSON.stringify
避免
JSON.stringify
返回格局谬误的 Unicode 字符串,ES2019 不是将未配对的代理代码点作为单个 UTF-16 代码单元返回,而是用 JSON 转义序列示意它们。
// 之前
console.log(JSON.stringify("\uD800")); // "�"
// es2019 之后
console.log(JSON.stringify("\uD800")); // "\ud800"
String.prototype.{trimStart,trimEnd}
trimStart()
办法从字符串的结尾删除空格。trimLeft()
是此办法的别名。办法移除原字符串左端的间断空白符并返回一个新字符串,并不会间接批改原字符串自身。
trimEnd()
办法从一个字符串的末端移除空白字符。trimRight()
是这个办法的别名。办法移除原字符串右端的间断空白符并返回,并不会间接批改原字符串自身。
- 根本应用
var str = "foo";
console.log(str.length); // 8
str = str.trimStart() // 等同于 str = str.trimLeft();
console.log(str.length); // 5
console.log(str); // "foo"
var str = "foo";
alert(str.length); // 8
str = str.trimRight(); // 或写成 str = str.trimEnd();
console.log(str.length); // 6
console.log(str); // 'foo'
- 兼容性
Array.prototype.{flat,flatMap}
flat
flat
: 办法会依照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。语法:
var newArray = arr.flat([depth]
入参
depth
(可选):指定提取嵌套数组的构造深度,默认值为 1。返回:一个蕴含将数组与子数组中所有元素的新数组。
flat
根本应用
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
// 应用 Infinity,可开展任意深度的嵌套数组
var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 移除数组中的空项
var arr5 = [1, 2, , 4, 5];
arr5.flat(); // [1, 2, 4, 5]
flatMap
办法首先应用映射函数映射每个元素,而后将后果压缩成一个新数组。它与 map 连着深度值为 1 的 flat 简直雷同,但
flatMap
通常在合并成一种办法的效率略微高一些。
- 语法
/**
参数:callback
能够生成一个新数组中的元素的函数,能够传入三个参数:currentValue
以后正在数组中解决的元素
index 可选
可选的。数组中正在解决的以后元素的索引。array 可选
可选的。被调用的 map 数组
thisArg 可选
可选的。执行 callback 函数时 应用的 this 值。返回:一个新的数组,其中每个元素都是回调函数的后果,并且构造深度 depth 值为 1。*/
var new_array = arr.flatMap(function callback(currentValue[, index[, array]]) {// return element for new_array}[, thisArg])
- 根本应用
var arr1 = [1, 2, 3, 4];
arr1.map(x => [x * 2]);
// [[2], [4], [6], [8]]
arr1.flatMap(x => [x * 2]);
// [2, 4, 6, 8]
// 只有一层 flattened
arr1.flatMap(x => [[x * 2]]);
// [[2], [4], [6], [8]]
- 兼容性
ES9 新个性(2018 公布)
非法转义序列的订正(Lifting template literal restriction)
ES2018 对于非法转义序列的订正:
带标签的模版字符串应该容许嵌套反对常见转义序列的语言(例如 DSLs、LaTeX)。ECMAScript 提议模版字面量订正(第 4 阶段,将要集成到 ECMAScript 2018 规范) 移除对 ECMAScript 在带标签的模版字符串中转义序列的语法限度。
function latex(str) {return { "cooked": str[0], "raw": str.raw[0] }
}
latex`\unicode`
// 较老版本 es2016 或更早
// SyntaxError: malformed Unicode character escape sequence
// es2018
// {cooked: undefined, raw: "\\unicode"}
- 值得注意的是,这一转义序列限度只对带标签的模板字面量移除,而不包含不带标签的模板字面量:
let bad = `bad escape sequence: \unicode`; // 报错 Uncaught SyntaxError: Invalid Unicode escape sequence
正则表达式\s
or (dotAll
)
正则表达式中点
.
匹配除回车外的任何单字符,标记s
扭转这种行为,容许行终止符的呈现.
/foo.bar/.test('foo\nbar');
// → false
/foo.bar/s.test('foo\nbar');
// → true
dotAll
:dotAll
属性表明是否在正则表达式中一起应用 ”s
“ 修饰符(引入 / s 修饰符,使得. 能够匹配任意单个字符)。dotAll
是一个只读的属性,属于单个正则表达式实例。
const re = /foo.bar/s; // Or, `const re = new RegExp('foo.bar', 's');`.
re.test('foo\nbar');
// → true
re.dotAll
// → true
re.flags
// → 's'
- 兼容性
正则表达式命名捕捉组(RegExp named capture groups)
ES2018 容许命名捕捉组应用符号
?<name>
,在关上捕捉括号(
后立刻命名,示例如下:任何匹配失败的命名组都将返回
undefined
。
exec
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
let result = re.exec('2015-01-02');
// result.groups.year === '2015';
// result.groups.month === '01';
// result.groups.day === '02';
// result[0] === '2015-01-02';
// result[1] === '2015';
// result[2] === '01';
// result[3] === '02';
replace
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
let result = '2015-01-02'.replace(re, '$<day>/$<month>/$<year>');
// result === '02/01/2015'
Rest/Spread Properties
ES2015 引入了 Rest 参数和扩大运算符。三个点(…)仅用于数组。Rest 参数语法容许咱们将一个不定数量的参数示意为一个数组。
// es2015
restFunc(1, 2, 3, 4, 5);
function restFunc(arg1, arg2, ...arg3) {
// arg1 = 1
// arg2 = 2
// arg3 = [3, 4, 5]
}
// 开展属性
const arr = [1, 4, -1, 5, 9];
console.log(Math.max(...values)); // 9
ES2018 为对象解构提供了和数组一样的 Rest 参数和 (…) 开展操作符
- rest 属性
let {x, y, ...z} = {x: 1, y: 2, a: 3, b: 4};
x; // 1
y; // 2
z; // {a: 3, b: 4}
- 开展 属性
let n = {x, y, ...z};
n; // {x: 1, y: 2, a: 3, b: 4}
RegExp 反向断言(RegExp Lookbehind Assertions)
- 正向断言(
?<=...
),它们确保蕴含在其中的模式位于申明之后的模式之前
// 匹配金额
/(?<=\$)\d+(\.\d*)?/.exec('$10.53');
// [10.53 ...]
/(?<=\$)\d+(\.\d*)?/.exec('¥10.53');
// null
- 反向断言(
?<!...
),另一方面,请确保其中的模式不在该断言之后的模式之前
/(?<!\$)\d+(?:\.\d*)/.exec('$10.53')
// [0.53 ...]
/(?<!\$)\d+(?:\.\d*)/.exec('¥10.53')
// [10.53 ...]
Unicode 属性在正则表达式中本义(RegExp Unicode Property Escapes)
es2018 之前,在正则表达式中本地拜访 Unicode 字符属性是不被容许的。
ES2018 增加了 Unicode 属性本义——模式为
\p{...}
和\P{...}
,在正则表达式中应用标记u
(unicode) 设置,在\p
块儿内,能够以键值对的形式设置须要匹配的属性而非具体内容。
const regex = /^\p{Decimal_Number}+$/u;
regex.test('????????????????????????????????????????????????????????????????');
// → true
const regex = /^\P{Decimal_Number}+$/u;
regex.test('Իմ օդաթիռը լի է օձաձկերով');
// → true
const regex = /^\p{Number}+$/u;
regex.test('²³¹¼½¾???????????????????????????????????????????????????????????????? ㉛㉜㉝ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿ');
// → true
Promise.prototype.finally
finally()
办法返回一个Promise
。在 promise 完结时,无论后果是 fulfilled 或者是 rejected,都会执行指定的回调函数。这为在Promise
是否胜利实现后都须要执行的代码提供了一种形式。这防止了同样的语句须要在
then()
和catch()
中各写一次的状况。留神: 在
finally
回调中throw
(或返回被回绝的 promise)将以throw()
指定的起因回绝新的 promise.
-
finally()
尽管与.then(onFinally, onFinally)
相似,它们不同的是:- 调用内联函数时,不须要屡次申明该函数或为该函数创立一个变量保留它。
- 因为无奈晓得
promise
的最终状态,所以finally
的回调函数中不接管任何参数,它仅用于无论最终后果如何都要执行的状况。 - 与
Promise.resolve(2).then(() => {}, () => {})
(resolved 的后果为undefined
)不同,Promise.resolve(2).finally(() => {})
resolved 的后果为2
。 - 同样,
Promise.reject(3).then(() => {}, () => {})
(resolved 的后果为undefined
),Promise.reject(3).finally(() => {})
rejected 的后果为3
。
- 根本应用
let isLoading = true;
fetch(myRequest).then(function(response) {var contentType = response.headers.get("content-type");
if(contentType && contentType.includes("application/json")) {return response.json();
}
throw new TypeError("Oops, we haven't got JSON!");
})
.then(function(json) {/* process your JSON further */})
.catch(function(error) {console.log(error); })
.finally(function() {isLoading = false;});
- 兼容性
异步迭代器(Asynchronous Iteration)
es2018 引入异步迭代器
for-await-of
,使得await
能够和for...of
循环一起应用,以串行的形式运行异步操作。
for await...of
语句 会在异步或者同步可迭代对象上创立一个迭代循环,包含String
,Array
,Array
-like 对象(比方arguments
或者NodeList
),TypedArray
,Map
,Set
和自定义的异步或者同步可迭代对象。其会调用自定义迭代钩子,并为每个不同属性的值执行语句 。 像await
表达式一样,这个语句只能在 async function 内应用。
- es2018 之前,谬误场景案例
在
async/await
的某些时刻,你可能尝试在同步循环中调用异步函数。
// 以下办法循环自身仍旧同步,并且会在外部异步函数实现之前全副调用实现
async function process(array) {for (let i of array) {await doSomething(i);
}
}
async function process(array) {
array.forEach(async i => {await doSomething(i);
});
}
- 根本应用
async function process(array) {for await (let i of array) {doSomething(i);
}
}
- 迭代异步可迭代对象
var asyncIterable = {[Symbol.asyncIterator]() {
return {
i: 0,
next() {if (this.i < 3) {return Promise.resolve({ value: this.i++, done: false});
}
return Promise.resolve({done: true});
}
};
}
};
(async function() {for await (num of asyncIterable) {console.log(num);
}
})();
// 0
// 1
// 2
- 迭代异步生成器
async function* asyncGenerator() {
var i = 0;
while (i < 3) {yield i++;}
}
(async function() {for await (num of asyncGenerator()) {console.log(num);
}
})();
// 0
// 1
// 2
- 兼容性
ES8 新个性(2017 公布)
Object.values
/Object.entries
Object.values
Object.values()
办法返回一个给定对象本身的所有可枚举属性值的数组,值的程序与应用for...in
循环的程序雷同 (区别在于 for-in 循环枚举原型链中的属性)。
Object.entries
Object.entries()办法返回一个给定对象本身可枚举属性的键值对数组,其排列与应用 [
for…in`](https://developer.mozilla.org… 循环遍历该对象时返回的程序统一(区别在于 for-in 循环还会枚举原型链中的属性)。
- 根本应用
var obj = {foo: 'bar', baz: 42};
console.log(Object.values(obj)); // ['bar', 42]
console.log(Object.entries(obj)); // [['foo', 'bar'], ['baz', 42] ]
- 兼容性
String padding
String.prototype.padStart
padStart()
办法用另一个字符串填充以后字符串(如果需要的话,会反复屡次),以便产生的字符串达到给定的长度。从以后字符串的左侧开始填充。
String.prototype.padEnd
padEnd()
办法会用一个字符串填充以后字符串(如果需要的话则反复填充),返回填充后达到指定长度的字符串。从以后字符串的开端(右侧)开始填充。
- 语法
/**
* 参数
*
* targetLength:以后字符串须要填充到的指标长度。如果这个数值小于以后字符串的长度,则返回以后字符串自身。* padString(可选):填充字符串。如果字符串太长,使填充后的字符串长度超过了指标长度,则只保留最左侧的局部,其余局部会被截断。此参数的缺省值为 " "(U+0020)。*/
str.padStart(targetLength [, padString])
str.padEnd(targetLength [, padString])
- 根本应用
'abc'.padStart(10); // "abc"
'abc'.padStart(10, "foo"); // "foofoofabc"
'abc'.padStart(6,"123465"); // "123abc"
'abc'.padStart(8, "0"); // "00000abc"
'abc'.padStart(1); // "abc"
'abc'.padEnd(10); // "abc"
'abc'.padEnd(10, "foo"); // "abcfoofoof"
'abc'.padEnd(6, "123456"); // "abc123"
'abc'.padEnd(1); // "abc"
- 兼容性
Object.getOwnPropertyDescriptors
Object.getOwnPropertyDescriptors()
办法用来获取一个对象的所有本身属性的描述符。入参:任意对象
返回:所指定对象的所有本身属性的描述符,如果没有任何本身属性,则返回空对象。
- 根本应用
// Object.assign() 办法只能拷贝源对象的可枚举的本身属性,同时拷贝时无奈拷贝属性的个性们,而且拜访器属性会被转换成数据属性,也无奈拷贝源对象的原型,该办法配合 Object.create() 办法能够实现下面说的这些。Object.create(Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
);
- 兼容性
函数 / 参数列表中容许逗号结尾(Trailing commas in function parameter lists and calls)
在对由版本控制系统治理的代码(git,subversion,mercurial 等)进行此更改的过程中,第 3 行和第 9 行的非常规 / 正文代码历史记录信息将更新为指向增加逗号的人(而是而不是最后增加参数的人)。
1: function clownPuppiesEverywhere(
2: param1,
3: param2, // updated to add a comma
4: param3 // updated to add new parameter
5: ) {/* ... */}
6:
7: clownPuppiesEverywhere(
8: 'foo',
9: 'bar', // updated to add a comma
10: 'baz' // updated to add new parameter
11: );
为了帮忙缓解此问题,某些其余语言(Python,D,Hack 等……可能还有其余……)增加了语法反对,以容许在这些参数列表中应用逗号结尾。这使代码提供者能够始终在这些每行参数列表之一中以尾随逗号完结参数增加,而不用放心代码归因问题
1: function clownPuppiesEverywhere(
2: param1,
3: param2, // Next parameter that's added only has to add a new line, not modify this line
5: ) {/* ... */}
6:
7: clownPuppiesEverywhere(
8: 'foo',
9: 'bar', // Next parameter that's added only has to add a new line, not modify this line
11: );
留神,该倡议仅与语法无关,并且不对语义进行任何更改,因而尾随逗号的存在对诸如之类的货色没有影响
<<function>>.length
。
Async functions
async 函数是应用
async
关键字申明的函数。async 函数是AsyncFunction
构造函数的实例,并且其中容许应用await
关键字。async
和await
关键字让咱们能够用一种更简洁的形式写出基于Promise
的异步行为,而无需刻意地链式调用promise
。async 函数可能蕴含 0 个或者多个
await
表达式。await 表达式会暂停整个 async 函数的执行过程并出让其控制权,只有当其期待的基于 promise 的异步操作被兑现或被回绝之后才会复原过程。promise 的解决值会被当作该 await 表达式的返回值。应用async
/await
关键字就能够在异步代码中应用一般的try
/catch
代码块。
await
关键字只在 async 函数内无效。如果你在 async 函数体之外应用它,就会抛出语法错误SyntaxError
。
async
/await
的目标为了简化应用基于 promise 的 API 时所需的语法。async
/await
的行为就如同搭配应用了生成器和 promise。
- 根本应用
async function foo() {return 1}
// 相当于
function foo() {return Promise.resolve(1)
}
// async 函数的函数体能够被看作是由 0 个或者多个 await 表达式宰割开来的。// 从第一行代码直到(并包含)第一个 await 表达式(如果有的话)都是同步运行的。// 这样的话,一个不含 await 表达式的 async 函数是会同步运行的。// 然而,如果函数体内有一个 await 表达式,async 函数就肯定会异步执行。async function foo() {await 1}
// 等价于
function foo() {return Promise.resolve(1).then(() => undefined)
}
- 兼容性
共享内存
和Atomics
(Shared memory and atomics)
共享内存
和Atomics
:引入了一个新的构造函数SharedArrayBuffer
和 具备辅助函数的命名空间对象Atomics
SharedArrayBuffer
对象用来示意一个通用的,固定长度的原始二进制数据缓冲区,相似于ArrayBuffer
对象,它们都能够用来在共享内存(shared memory)上创立视图。与ArrayBuffer
不同的是,SharedArrayBuffer
不能被拆散。
为了将一个
SharedArrayBuffer
对象从一个用户代理共享到另一个用户代理(另一个页面的主过程或者以后页面的一个worker
)从而实现共享内存,咱们须要使用postMessage
和结构化克隆算法(structured cloning)。
结构化克隆算法
接管被映射到一个新的SharedArrayBuffers
对象上的SharedArrayBuffers
对象与TypedArrays
对象。在这两种映射下,这个新的SharedArrayBuffer
对象会被传递到指标用户代理的接管函数上,导致在指标用户代理产生了一个新的公有SharedArrayBuffer
对象(正如ArrayBuffer
一样)。然而,这两个SharedArrayBuffer
对象指向的共享数据块其实是同一个,并且在某一代理中的一个块的副作用将最终导致另一个代理具备可见性。
Atomics
对象提供了一组静态方法对SharedArrayBuffer
和ArrayBuffer
对象进行原子操作。
这些原子操作属于
Atomics
模块。与个别的全局对象不同,Atomics
不是构造函数,因而不能应用 new 操作符调用,也不能将其当作函数间接调用。Atomics
的所有属性和办法都是动态的(与Math
对象一样)。
ES7 新个性(2016 公布)
Array.prototype.includes
includes()
办法用来判断一个数组是否蕴含一个指定的值,依据状况,如果蕴含则返回 true,否则返回 false。
- 语法
/**
* valueToFind:须要查找的元素值。* fromIndex(可选):从 fromIndex 索引处开始查找 valueToFind。如果为负值,则按升序从 array.length + fromIndex 的索引开始搜(即便从开端开始往前跳 fromIndex 的绝对值个索引,而后往后搜查)。默认为 0。* 返回:返回一个布尔值 Boolean,如果在数组中找到了(如果传入了 fromIndex,示意在 fromIndex 指定的索引范畴中找到了)则返回 true。*/
arr.includes(valueToFind[, fromIndex])
- 根本应用
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
[1, 2, NaN].includes(NaN); // true
- 如果
fromIndex
为负值,计算出的索引将作为开始搜寻searchElement
的地位。如果计算出的索引小于 0,则整个数组都会被搜寻。
// 计算索引小于 0
// array length is 3
// fromIndex is -100
// computed index is 3 + (-100) = -97
var arr = ['a', 'b', 'c'];
arr.includes('a', -100); // true
arr.includes('b', -100); // true
arr.includes('c', -100); // true
arr.includes('a', -2); // false
- 兼容性
求幂 (**)(Exponentiation operator)
求幂运算符(
**
)返回将第一个操作数加到第二个操作数的幂的后果。它等效于Math.pow
,不同之处在于它也承受 BigInts 作为操作数。求幂运算符是是 右联合的:
a ** b ** c
等于a ** (b ** c)
.
- 根本应用
2 ** 3 // 8
3 ** 2 // 9
3 ** 2.5 // 15.588457268119896
10 ** -1 // 0.1
NaN ** 2 // NaN
// 右联合性
2 ** 3 ** 2 // 512
2 ** (3 ** 2) // 512
(2 ** 3) ** 2 // 64
// 与一元运算符联合
-(2 ** 2) // -4
(-2) ** 2 // 4
- 在 JavaScript 里,你不可能写出一个不明确的求幂表达式。这就是说,你不能立即将一个一元运算符(
+/-/~/!/delete/void/typeof
)放在基数前,这样做只会导致一个语法错误。
-2 ** 2;
// 4 in Bash, -4 in other languages.
// This is invalid in JavaScript, as the operation is ambiguous.
-(2 ** 2);
// -4 in JavaScript and the author's intention is unambiguous.
- 兼容性
参考
- TC39
- MDN