新鮮出爐,整合近幾年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.
  • 兼容性

參考

相關文章
相關標籤/搜索