此文初衷以下几点:javascript
- 源于为了了解不一样阶段浏览器对不有些方法的支持状况,方便快速定位不一样浏览器下的兼容问题;
- 同时作为文档查阅,能更清楚的了解每一阶段的新特性;
- 帮助你们面试加分,试问熟知每一个阶段的更新细节总归会给面试官好印象;
以此与你们共勉,有帮助的话顺手给个赞,谢谢~~html
ECMAScript 语言规范的第 11 版本。
matchAll
方法返回一个包含全部匹配正则表达式的结果及分组捕获组的迭代器。入参:
regexp
为正则表达式对象。若是所传参数不是一个正则表达式对象,则会隐式地使用new RegExp(obj)
将其转换为一个RegExp
。java返回:一个迭代器(不可重用,结果耗尽须要再次调用方法,获取一个新的迭代器)。git
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
异常github
/i
:忽略大小写/g
:全文查找出现的全部匹配字符/m
:多行查找/ig
:全文查找、忽略大小写标准用法的import
导入的模块是静态的,会使全部被导入的模块,在加载时就被编译(没法作到按需编译,下降首页加载速度)。有些场景中,你可能但愿根据条件导入模块或者按需导入模块,这时你可使用动态导入代替静态导入。下面的是你可能会须要动态导入的场景:web
使用场景面试
function callback() { // 一样支持 await 写法 import("moduleB") .then((module) => { // todo }) .catch((err) => { // load error }); }
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
模块重定向
// 若是咱们想要在当前模块中,导出指定导入模块的默认导出(等因而建立了一个“重定向”): // module "redirect-module.js" export {default} from './other-module'; export * from './other-module'; export * as otherName from './other-module';
入参:一个可迭代的对象,其中每一个成员都是Promise
返回:一个在全部给定的
promise
都已经fulfilled
或rejected
后的promise
,并带有一个对象数组,每一个对象表示对应的promise
结果。算法当您有多个彼此不依赖的异步任务成功完成时,或者您老是想知道每一个
promise
的结果时,一般使用它。json相比之下,
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
最新的 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
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
包含全局的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 方法! }
可选链操做符(?.
)容许读取位于链接对象链深处的属性的值,而没必要明确验证链中的每一个引用是否有效。?.
操做符的功能相似于.
链式操做符,不一样之处在于,在引用为空(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];
空值合并操做符(??
)是一个逻辑操做符,当左侧的操做数为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); // “暗之城”
catch
binding(catch 绑定可选)容许在不使用catch
绑定的状况下省略绑定,catch
的参数能够忽略
// 以往 try { } catch (error) { } // 如今支持语法,catch 能够不使用抛出的 error try { // ... } catch { // ... }
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 }
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]]
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'
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'
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参数和(...)展开操做符
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 }
?<=...
),它们确保包含在其中的模式位于声明以后的模式以前// 匹配金额 /(?<=\$)\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 ...]
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; });
es2018引入异步迭代器for-await-of
,使得await
能够和for...of
循环一块儿使用,以串行的方式运行异步操做。
for await...of
语句会在异步或者同步可迭代对象上建立一个迭代循环,包括String
,Array
,Array
-like 对象(好比arguments
或者NodeList
),TypedArray
,Map
,Set
和自定义的异步或者同步可迭代对象。其会调用自定义迭代钩子,并为每一个不一样属性的值执行语句。像await
表达式同样,这个语句只能在 async function内使用。
在
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
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.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) );
在对由版本控制系统管理的代码(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函数是使用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
对象同样)。
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
求幂运算符(**
)返回将第一个操做数加到第二个操做数的幂的结果。它等效于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
+/-/~/!/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.