乐趣区

关于javascript:新鲜出炉整合近几年ES711的新特性

此文初衷如下几点:

  1. 源于为了理解不同阶段浏览器对不有些办法的反对状况,不便疾速定位不同浏览器下的兼容问题;
  2. 同时做为文档查阅,能更分明的理解每一阶段的新个性;
  3. 帮忙大家面试加分,试问熟知每个阶段的更新细节总归会给面试官好印象;

以此与大家共勉,有帮忙的话棘手给个赞,谢谢~~

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 都曾经 fulfilledrejected后的 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中:能够通过 windowself 或者 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 逻辑操作符类似,当左表达式不为 nullundefined 时,不会对右表达式进行求值。

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 的 DoubleStringCharacterSingleStringCharacter生产能够扩大为容许不本义的 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相似 ArrayMap 或者其它实现了可迭代协定的可迭代对象。

返回:一个由该迭代对象条目提供对应属性的新对象。

  • 根本应用
// 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}

  1. 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]
  1. 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]]
  1. 兼容性


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
  • dotAlldotAll 属性表明是否在正则表达式中一起应用 ”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 语句 会在异步或者同步可迭代对象上创立一个迭代循环,包含 StringArrayArray-like 对象(比方 arguments 或者NodeList),TypedArrayMapSet 和自定义的异步或者同步可迭代对象。其会调用自定义迭代钩子,并为每个不同属性的值执行语句 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 关键字。asyncawait 关键字让咱们能够用一种更简洁的形式写出基于 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 对象提供了一组静态方法对 SharedArrayBufferArrayBuffer 对象进行原子操作。

这些原子操作属于 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
退出移动版