新鲜出炉,整合近几年ES7-11的新特性

此文初衷以下几点:javascript

  1. 源于为了了解不一样阶段浏览器对不有些方法的支持状况,方便快速定位不一样浏览器下的兼容问题;
  2. 同时作为文档查阅,能更清楚的了解每一阶段的新特性;
  3. 帮助你们面试加分,试问熟知每一个阶段的更新细节总归会给面试官好印象;

以此与你们共勉,有帮助的话顺手给个赞,谢谢~~html

ES11新特性(2020发布)

ECMAScript 语言规范的第 11 版本。

String.prototype.matchAll(regexp)

matchAll方法返回一个包含全部匹配正则表达式的结果及分组捕获组的迭代器。

入参:regexp为正则表达式对象。若是所传参数不是一个正则表达式对象,则会隐式地使用 new RegExp(obj) 将其转换为一个 RegExpjava

返回:一个迭代器(不可重用,结果耗尽须要再次调用方法,获取一个新的迭代器)。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:全文查找、忽略大小写

错误使用参考

  • 兼容性

matchAll 兼容性

Dynamic import 动态引入

标准用法的 import导入的模块是静态的,会使全部被导入的模块,在加载时就被编译(没法作到按需编译,下降首页加载速度)。

有些场景中,你可能但愿根据条件导入模块或者按需导入模块,这时你可使用动态导入代替静态导入。下面的是你可能会须要动态导入的场景:web

  • 使用场景面试

    • 当静态导入的模块很明显的下降了代码的加载速度且被使用的可能性很低,或者并不须要立刻使用它。
    • 当静态导入的模块很明显的占用了大量系统内存且被使用的可能性很低。
    • 当被导入的模块,在加载时并不存在,须要异步获取
    • 当导入模块的说明符,须要动态构建。(静态导入只能使用静态说明符)
    • 当被导入的模块有反作用(这里说的反作用,能够理解为模块中会直接运行的代码),这些反作用只有在触发了某些条件才被须要时。(原则上来讲,模块不能有反作用,可是不少时候,你没法控制你所依赖的模块的内容)
  • 常规用做异步按需加载
function callback() {
  // 一样支持 await 写法
  import("moduleB")
    .then((module) => {
      // todo
    })
    .catch((err) => {
      // load error
    });
}
  • 兼容性

import 浏览器兼容状况

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的结果时,一般使用它。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
  • 兼容性

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" }
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关于非法转义序列的修订:

带标签的模版字符串应该容许嵌套支持常见转义序列的语言(例如DSLsLaTeX)。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 模块。与通常的全局对象不一样, 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.
  • 兼容性

参考

相关文章
相关标签/搜索