【轉(zhuǎn)載】ES6~ES12的版本記錄

ES6 —— ES12

原文鏈接:http://www.reibang.com/p/2514a5080c29

ECMAScript 是一種由 Ecma 國(guó)際(前身為歐洲計(jì)算機(jī)制造商協(xié)會(huì))通過(guò) ECMA-262 標(biāo)準(zhǔn)化的腳本程序設(shè)計(jì)語(yǔ)言危彩。這種語(yǔ)言在萬(wàn)維網(wǎng)上應(yīng)用廣泛病袄,它往往被稱為 JavaScriptJScript筹吐,所以它可以理解為是 JavaScript 的一個(gè)標(biāo)準(zhǔn),但實(shí)際上后兩者是 ECMA-262 標(biāo)準(zhǔn)的實(shí)現(xiàn)和擴(kuò)展彰阴。

ES6(ES2015)

  1. letconst

    var let const
    變量提升 × ×
    全局變量 × ×
    重復(fù)聲明 × ×
    重新賦值 ×
    暫時(shí)性死區(qū) ×
    塊作用域 ×
    只聲明不初始化 ×

    暫時(shí)性死區(qū)(TDZ):ES6 明確規(guī)定焙矛,如果區(qū)塊中存在 let 命令炼蹦,這個(gè)區(qū)塊對(duì)這些命令聲明的變量逮壁,從一開始就形成了封閉作用域颓遏。只要一進(jìn)入當(dāng)前作用域徐矩,所要使用的變量就已經(jīng)存在了,但是不可獲取叁幢,只有等到聲明變量的那一行代碼出現(xiàn)滤灯,才可以獲取和使用該變量。

  2. 類(Class
    ES6 之前曼玩,如果我們要生成一個(gè)實(shí)例對(duì)象鳞骤,傳統(tǒng)的方法就是寫一個(gè)構(gòu)造函數(shù),例子如下:

    function Person(name, age) {
        this.name = name
        this.age = age
    }
    Person.prototype.information = function () {
        return 'My name is ' + this.name + ', I am ' + this.age
    }
    
    

    但是在 ES6 之后黍判,我們只需要寫成以下形式:

    class Person {
        constructor(name, age) {
            this.name = name
            this.age = age
        }
        information() {
            return 'My name is ' + this.name + ', I am ' + this.age
        }
    }
    
    
  3. 箭頭函數(shù)(Arrow function)

  4. 函數(shù)參數(shù)默認(rèn)值(Function parameter defaults)

  5. 模板字符串(Template string)

  6. 解構(gòu)賦值(Destructuring assignment)

  7. 模塊化(Module)

  8. 擴(kuò)展操作符(Spread operator)

  9. Promise
    PromiseES6 提供的一種異步解決方案豫尽,比回調(diào)函數(shù)更加清晰明了。
    所謂 Promise顷帖,簡(jiǎn)單說(shuō)就是一個(gè)容器美旧,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果。從語(yǔ)法上說(shuō)贬墩,Promise 是一個(gè)對(duì)象榴嗅,從它可以獲取異步操作的消息。
    Promise 提供統(tǒng)一的 API陶舞,各種異步操作都可以用同樣的方法進(jìn)行處理嗽测。Promise 對(duì)象有以下兩個(gè)特點(diǎn):

    • 對(duì)象的狀態(tài)不受外界影響。Promise 對(duì)象代表一個(gè)異步操作吊说,有三種狀態(tài):Pending(進(jìn)行中)论咏、Resolved(已完成优炬,又稱 Fulfilled)和 Rejected(已失敯渚)。只有異步操作的結(jié)果蠢护,可以決定當(dāng)前是哪一種狀態(tài)雅宾,任何其他操作都無(wú)法改變這個(gè)狀態(tài)。
    • 一旦狀態(tài)改變葵硕,就不會(huì)再變眉抬,任何時(shí)候都可以得到這個(gè)結(jié)果。Promise 對(duì)象的狀態(tài)改變懈凹,只有兩種可能:從 Pending 變?yōu)?Resolved 和從 Pending 變?yōu)?Rejected蜀变。

    缺點(diǎn):首先,無(wú)法取消 Promise介评,一旦新建它就會(huì)立即執(zhí)行库北,無(wú)法中途取消爬舰。其次,如果不設(shè)置回調(diào)函數(shù)寒瓦,Promise 內(nèi)部拋出的錯(cuò)誤情屹,不會(huì)反應(yīng)到外部。第三杂腰,當(dāng)處于 Pending 狀態(tài)時(shí)垃你,無(wú)法得知目前進(jìn)展到哪一個(gè)階段(剛剛開始還是即將完成)。

    var promise = new Promise(function(resolve, reject) {
      // ... some code
      if (/* 異步操作成功 */){
        resolve(value);
      } else {
        reject(error);
      }
    })
    
    promise.then(function(value) {
      // success
    }, function(error) {
      // failure
    })
    
    
    • Promise.all():用于將多個(gè) Promise 實(shí)例喂很,包裝成一個(gè)新的 Promise 實(shí)例惜颇。只有這6個(gè)實(shí)例的狀態(tài)都變成 fulfilled,或者其中有一個(gè)變?yōu)?rejected少辣,才會(huì)調(diào)用 Promise.all 方法后面的回調(diào)函數(shù)官还。

    • Promise.race():將多個(gè) Promise 實(shí)例,包裝成一個(gè)新的 Promise 實(shí)例毒坛。var p = Promise.race([p1, p2, p3]) 只要 p1望伦、p2、p3 之中有一個(gè)實(shí)例率先改變狀態(tài)煎殷,p 的狀態(tài)就跟著改變屯伞。那個(gè)率先改變的 Promise 實(shí)例的返回值,就傳遞給 p 的回調(diào)函數(shù)豪直。

    • Promise.resolve():將現(xiàn)有對(duì)象轉(zhuǎn)為 Promise 對(duì)象劣摇。

      Promise.resolve('foo')
      // 等價(jià)于
      new Promise(resolve => resolve('foo'))
      
      
    • Promise. reject():將現(xiàn)有對(duì)象轉(zhuǎn)為 Promise 對(duì)象,該實(shí)例的狀態(tài)為 rejected弓乙。

      var p = Promise.reject('出錯(cuò)了');
      // 等價(jià)于
      var p = new Promise((resolve, reject) => reject('出錯(cuò)了'))
      
      
    • done():總是處于回調(diào)鏈的尾端末融,保證拋出任何可能出現(xiàn)的錯(cuò)誤

    • finally():用于指定不管 Promise 對(duì)象最后狀態(tài)如何,都會(huì)執(zhí)行的操作暇韧。它與 done 方法的最大區(qū)別勾习,它接受一個(gè)普通的回調(diào)函數(shù)作為參數(shù),該函數(shù)不管怎樣都必須執(zhí)行懈玻。

    • Promise.try():讓同步函數(shù)同步執(zhí)行巧婶,異步函數(shù)異步執(zhí)行,并且讓它們具有統(tǒng)一的 API

      const f = () => console.log('now');
      Promise.try(f);
      console.log('next');
      // now
      // next
      
      
  10. for…of

```
const array1 = ['a', 'b', 'c']
for (const element of array1) {
      console.log(element)
}

```

for ... in ; for ... of 區(qū)別

*   for ... in 獲取的是對(duì)象的鍵名涂乌;for ... of 遍歷獲取的是對(duì)象的鍵值
*   for ... in 會(huì)遍歷對(duì)象的整個(gè)原型鏈艺栈,性能非常差,不推薦使用;而 for ... of 只遍歷當(dāng)前對(duì)象,不會(huì)遍歷原型鏈
*   對(duì)于數(shù)組的遍歷骡澈,for ... in 會(huì)返回?cái)?shù)組中所有可枚舉的屬性(包括原型鏈上可枚舉的屬性);for ... of 只返回?cái)?shù)組的下標(biāo)對(duì)應(yīng)的屬性值
*   對(duì)于普通對(duì)象毅人,沒(méi)有部署原生的 iterator 接口漾唉,直接使用 for...of 會(huì)報(bào)錯(cuò),也可以使用 Object.keys(obj) 方法將對(duì)象的鍵名生成一個(gè)數(shù)組堰塌,然后遍歷這個(gè)數(shù)組
*   forEach 循環(huán)無(wú)法中途跳出赵刑,break 命令或 return 命令都不能奏效;for...of 循環(huán)可以與 break场刑、continue 和 return 配合使用般此,跳出循環(huán)
*   for...in 循環(huán)主要是為了遍歷對(duì)象而生,不適用于遍歷數(shù)組牵现;for...of 循環(huán)可以用來(lái)遍歷數(shù)組铐懊、類數(shù)組對(duì)象,字符串瞎疼、Set科乎、Map 以及 Generator 對(duì)象
  1. Symbol
    symbol 是一種基本數(shù)據(jù)類型,表示獨(dú)一無(wú)二的值贼急。Symbol() 函數(shù)會(huì)返回 symbol 類型的值茅茂,該類型具有靜態(tài)屬性和靜態(tài)方法。
    每個(gè)從 Symbol() 返回的 symbol 值都是唯一的太抓。一個(gè) symbol 值能作為對(duì)象屬性的標(biāo)識(shí)符空闲;這是該數(shù)據(jù)類型僅有的目的。
```
const symbol1 = Symbol();
const symbol2 = Symbol(42);
const symbol3 = Symbol('foo');

console.log(typeof symbol1);  // "symbol"
console.log(symbol3.toString());  // "Symbol(foo)"
console.log(Symbol('foo') === Symbol('foo'));  // false

```
  1. 迭代器(Iterator)/ 生成器(Generator)
    迭代器(Iterator)是一種迭代的機(jī)制走敌,為各種不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的訪問(wèn)機(jī)制碴倾。任何數(shù)據(jù)結(jié)構(gòu)只要內(nèi)部有 Iterator 接口,就可以完成依次迭代操作掉丽。
    一旦創(chuàng)建跌榔,迭代器對(duì)象可以通過(guò)重復(fù)調(diào)用 next() 顯式地迭代,從而獲取該對(duì)象每一級(jí)的值捶障,直到迭代完僧须,返回 { value: undefined, done: true }
```
function* makeRangeIterator(start = 0, end = Infinity, step = 1) {
    for (let i = start; i < end; i += step) {
        yield i;
    }
}
var a = makeRangeIterator(1,10,2)
a.next() // {value: 1, done: false}
a.next() // {value: 3, done: false}
a.next() // {value: 5, done: false}
a.next() // {value: 7, done: false}
a.next() // {value: 9, done: false}
a.next() // {value: undefined, done: true}

```
  1. Set / WeakSet
    Set 對(duì)象允許你存儲(chǔ)任何類型的唯一值残邀,無(wú)論是原始值或者是對(duì)象引用皆辽。
```
const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
console.log([...new Set(numbers)])  // [2, 3, 4, 5, 6, 7, 32]

```

`WeakSet` 結(jié)構(gòu)與 `Set` 類似柑蛇,但區(qū)別有以下兩點(diǎn):

*   `WeakSet` 對(duì)象中只能存放對(duì)象引用芥挣,不能存放值,而 `Set` 對(duì)象都可以耻台。
*   `WeakSet` 對(duì)象中存儲(chǔ)的對(duì)象值都是被弱引用的空免,如果沒(méi)有其他的變量或?qū)傩砸眠@個(gè)對(duì)象值,則這個(gè)對(duì)象值會(huì)被當(dāng)成垃圾回收掉盆耽。正因?yàn)檫@樣蹋砚,`WeakSet` 對(duì)象是無(wú)法被枚舉的扼菠,沒(méi)有辦法拿到它包含的所有元素。

```
const ws = new WeakSet()
const obj = {}
const foo = {}

ws.add(window)
ws.add(obj)

ws.has(window)  // true
ws.has(foo)  // false, 對(duì)象 foo 并沒(méi)有被添加進(jìn) ws 中 

ws.delete(window)  // 從集合中刪除 window 對(duì)象
ws.has(window)  // false, window 對(duì)象已經(jīng)被刪除了

ws.clear()  // 清空整個(gè) WeakSet 對(duì)象

```
  1. Map / WeakMap
    Map 對(duì)象保存鍵值對(duì)坝咐。任何值(對(duì)象或者原始值) 都可以作為一個(gè)鍵或一個(gè)值循榆。甚至可以使用 NaN 來(lái)作為鍵值。
```
const myMap = new Map();
myMap.set(NaN, "not a number");
myMap.get(NaN);  // "not a number"

const otherNaN = Number("foo");
myMap.get(otherNaN);  // "not a number"

```

`WeakMap` 對(duì)象是一組鍵 / 值對(duì)的集合墨坚,其中的鍵是弱引用的秧饮。其鍵必須是對(duì)象,而值可以是任意的泽篮。跟 `Map` 的區(qū)別與 `Set` 跟 `WeakSet` 的區(qū)別相似盗尸。

```
const o1 = {};
const o2 = function(){};
const o3 = window;

const wm1 = new WeakMap();
wm1.set(o1, 37);
wm1.has(o1);  // true
wm1.delete(o1);
wm1.has(o1);  // false

wm1.set(o2, "azerty");
wm1.get(o2);  // "azerty"
wm1.has(o2);  // true

const wm2 = new WeakMap();
wm2.set(o1, o2);  // value可以是任意值,包括一個(gè)對(duì)象
wm2.get(o2);  // undefined,wm2中沒(méi)有o2這個(gè)鍵
wm2.has(o2);  // false

wm2.set(o3, undefined);
wm2.get(o3);  // undefined,值就是undefined
wm2.has(o3);  // true (即使值是undefined)

wm2.set(wm1, wm2);  // 鍵和值可以是任意對(duì)象,甚至另外一個(gè)WeakMap對(duì)象

const wm3 = new WeakMap();
wm3.set(o1, 37);
wm3.get(o1);  // 37
wm3.clear();
wm3.get(o1);  // undefined,wm3已被清空

```
  1. Proxy / Reflect
    Proxy 對(duì)象用于定義基本操作的自定義行為(如屬性查找,賦值帽撑,枚舉泼各,函數(shù)調(diào)用等)。
    Reflect 是一個(gè)內(nèi)置的對(duì)象亏拉,它提供攔截 JavaScript 操作的方法扣蜻。這些方法與 Proxy 的方法相同。Reflect 不是一個(gè)函數(shù)對(duì)象及塘,因此它是不可構(gòu)造的弱贼。
```
const observe = (data, callback) => {
  return new Proxy(data, {
        get(target, key) {
            return Reflect.get(target, key)
        },
        set(target, key, value, proxy) {
              callback(key, value);
              target[key] = value;
                return Reflect.set(target, key, value, proxy)
        }
  })
}

const FooBar = { open: false };
const FooBarObserver = observe(FooBar, (property, value) => {
  property === 'open' && value 
      ? console.log('FooBar is open!!!') 
      : console.log('keep waiting');
});
console.log(FooBarObserver.open)  // false
FooBarObserver.open = true  // FooBar is open!!!
FooBarObserver.open = false // keep waiting

```
  1. Regex對(duì)象的擴(kuò)展
*   u 修飾符:
    為了處理碼點(diǎn)大于 `\uFFFF` 的 `Unicode` 字符(也就是說(shuō),會(huì)正確處理四個(gè)字節(jié)的 `UTF-16` 編碼)磷蛹;`\uD83D\uDC2A` 是一個(gè)字符吮旅,但是 `es5` 不支持四個(gè)字節(jié)的 `UTF-16`,會(huì)將其識(shí)別成兩個(gè)字符味咳;加了 `u` 修飾符之后庇勃,`es6` 會(huì)將其識(shí)別成一個(gè)字符。

    ```
    // i 修飾符:不區(qū)分大小寫
    /[a-z]/i.test('\u212A')  // false
    /[a-z]/iu.test('\u212A')  // true

    ```

*   y 修飾符:“粘連”(sticky)修飾符
    `y` 修飾符的作用與 `g` 修飾符類似槽驶,也是全局匹配责嚷,后一次匹配都從上一次匹配成功的下一個(gè)位置開始。不同之處在于掂铐,`g` 修飾符只要剩余位置中存在匹配就可罕拂,而 `y` 修飾符確保匹配必須從剩余的第一個(gè)位置開始,這也就是“粘連”的涵義全陨。

    ```
    var s = 'aaa_aa_a';
    var r1 = /a+/g;
    var r2 = /a+/y;

    r1.exec(s) // ["aaa"]
    r2.exec(s) // ["aaa"]

    r1.exec(s) // ["aa"]
    r2.exec(s) // null

    ```

*   查看RegExp構(gòu)造函數(shù)的修飾符

    ```
    new RegExp(/abc/ig, 'i').flags  //  "i"

    ```
  1. Array 對(duì)象的擴(kuò)展
*   `Array.from()`
    用于將兩類對(duì)象轉(zhuǎn)為真正的數(shù)組:類似數(shù)組的對(duì)象(`array-like object`)和可遍歷(`iterable`)的對(duì)象(包括 `ES6` 新增的數(shù)據(jù)結(jié)構(gòu) `Set` 和 `Map`)爆班。

    ```
    Array.from('foo')  //  ["f", "o", "o"]
    // 擴(kuò)展運(yùn)算符(...)也可以將某些數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)為數(shù)組
    [ ...document.querySelectorAll('div') ]  //  NodeList對(duì)象
    Array.from({ length: 3 })  //  [ undefined, undefined, undefined ]
    Array.from([1, 2, 3], x => x + x)  //  [2, 4, 6]

    ```

*   `Array.of()`:用于將一組值,轉(zhuǎn)換為數(shù)組

    ```
    Array.of()  //  []
    Array.of(3, 11, 8)  //  [3,11,8]
    Array.of(3)  //  [3]
    Array.of(3).length  //  1

    // 這個(gè)方法的主要目的辱姨,是彌補(bǔ)數(shù)組構(gòu)造函數(shù)Array()的不足柿菩。因?yàn)閰?shù)個(gè)數(shù)的不同,會(huì)導(dǎo)致Array()的行為有差異雨涛。
    Array()  //  []
    Array(7)  //  [empty, empty, empty, empty, empty, empty]
    Array(3, 11, 8)  //  [3, 11, 8]

    ```

*   數(shù)組實(shí)例的 `copyWithin()`
    在當(dāng)前數(shù)組內(nèi)部枢舶,將指定位置的成員復(fù)制到其他位置(會(huì)覆蓋原有成員)懦胞,然后返回當(dāng)前數(shù)組,會(huì)修改當(dāng)前數(shù)組凉泄。
    `Array.prototype.copyWithin(target, start = 0, end = this.length)`
    它接受三個(gè)參數(shù)躏尉。這三個(gè)參數(shù)都應(yīng)該是數(shù)值,如果不是后众,會(huì)自動(dòng)轉(zhuǎn)為數(shù)值醇份。

    1.  target(必需):從該位置開始替換數(shù)據(jù)。
    2.  start(可選):從該位置開始讀取數(shù)據(jù)吼具,默認(rèn)為0僚纷。如果為負(fù)值,表示倒數(shù)拗盒。
    3.  end(可選):到該位置前停止讀取數(shù)據(jù)怖竭,默認(rèn)等于數(shù)組長(zhǎng)度。如果為負(fù)值陡蝇,表示倒數(shù)痊臭。

    ```
    ['a', 'b', 'c', 'd', 'e'].copyWithin(0, 3, 4)  //  ["d", "b", "c", "d", "e"]
    [1, 2, 3, 4, 5].copyWithin(0, 3)  //  [4, 5, 3, 4, 5]
    [1, 2, 3, 4, 5].copyWithin(0, -2, -1)  //  [4, 2, 3, 4, 5]

    ```

*   數(shù)組實(shí)例的 `find() 和 findIndex()`

*   數(shù)組實(shí)例的 `fill()`:`fill` 方法使用給定值,填充一個(gè)數(shù)組

    ```
    ['a', 'b', 'c'].fill(7)  //  [7, 7, 7]
    new Array(3).fill(7)  //  [7, 7, 7]
    // 可以接受第二個(gè)和第三個(gè)參數(shù)登夫,用于指定填充的起始位置和結(jié)束位置
    ['a', 'b', 'c'].fill(7, 1, 2)  //  ['a', 7, 'c']
    [1, 2, 3, 4].fill(5, 1)  //  [1, 5, 5, 5]

    ```

*   數(shù)組實(shí)例的 `entries()广匙,keys() 和 values()`

    ```
    /*
    * 用于遍歷數(shù)組,都返回一個(gè)遍歷器對(duì)象恼策,可以用 for...of 循環(huán)進(jìn)行遍歷
    * 唯一的區(qū)別是 keys() 是對(duì)鍵名的遍歷鸦致、values() 是對(duì)鍵值的遍歷、entries() 是對(duì)鍵值對(duì)的遍歷
    */
    for (let index of ['a', 'b'].keys()) {
      console.log(index);
    }
    // 0
    // 1

    for (let elem of ['a', 'b'].values()) {
      console.log(elem);
    }
    // 'a'
    // 'b'

    for (let [index, elem] of ['a', 'b'].entries()) {
      console.log(index, elem);
    }
    // 0 "a"
    // 1 "b"

    ```

*   數(shù)組的空位:明確將空位轉(zhuǎn)為 `undefined`

ES7(ES2016)

  1. 數(shù)組實(shí)例的 includes()
    返回一個(gè)布爾值涣楷,表示某個(gè)數(shù)組是否包含給定的值分唾,與字符串的 includes 方法類似

    [1, 2, 3].includes(2);  //  true
    [1, 2, 3].includes(4);  //  false
    [1, 2, NaN].includes(NaN);  //  true
    
    

    該方法的第二個(gè)參數(shù)表示搜索的起始位置,默認(rèn)為0狮斗。如果第二個(gè)參數(shù)為負(fù)數(shù)绽乔,則表示倒數(shù)的位置,如果這時(shí)它大于數(shù)組長(zhǎng)度(比如第二個(gè)參數(shù)為-4碳褒,但數(shù)組長(zhǎng)度為3)折砸,則會(huì)重置為從0開始。

    [1, 2, 3].includes(3, 3);  // false
    [1, 2, 3].includes(3, -1); // true
    
    

    另外沙峻,MapSet 數(shù)據(jù)結(jié)構(gòu)有一個(gè) has 方法睦授,需要注意與 includes 區(qū)分。

    1. Map 結(jié)構(gòu)的has方法专酗,是用來(lái)查找鍵名的睹逃,比如 Map.prototype.has(key)、WeakMap.prototype.has(key)祷肯、Reflect.has(target, propertyKey)沉填。
    2. Set 結(jié)構(gòu)的 has 方法,是用來(lái)查找值的佑笋,比如 Set.prototype.has(value)翼闹、WeakSet.prototype.has(value)
  2. 冪運(yùn)算符 **

    console.log(2**10) // 1024
    console.log(Math.pow(2, 10)) // 1024
    
    
  3. 模板字符串(Template string)
    ES7 起蒋纬,帶標(biāo)簽的模版字面量遵守以下轉(zhuǎn)義序列的規(guī)則:

    • Unicode 字符以 "\u" 開頭猎荠,例如 \u00A9
    • Unicode 碼位用"\u{}"表示,例如 \u{2F804}
    • 十六進(jìn)制以 "\x" 開頭蜀备,例如 \xA9
    • 八進(jìn)制以 "" 和數(shù)字開頭关摇,例如 \251

ES8(ES2017)

  1. async / await
    Promise 的語(yǔ)法糖,專門解決回調(diào)地獄碾阁,async 函數(shù)返回一個(gè) Promise 對(duì)象输虱。async 函數(shù)內(nèi)部 return 語(yǔ)句返回的值,會(huì)成為 then 方法回調(diào)函數(shù)的參數(shù)脂凶。

    async function f() {
      return 'hello world';
    }
    f().then(v => console.log(v))  //  "hello world"
    // 同時(shí)觸發(fā)寫法
    let [foo, bar] = await Promise.all([getFoo(), getBar()]);
    
    
  2. Object.values():返回一個(gè)給定對(duì)象自身的所有可枚舉屬性值的數(shù)組

    const object1 = {
      a: 'somestring',
      b: 42,
      c: false
    }
    console.log(Object.values(object1)) // ["somestring", 42, false]
    
    
  3. Object.entries():返回一個(gè)給定對(duì)象自身可枚舉屬性的鍵值對(duì)數(shù)組

    const object1 = {
        a: 'somestring',
        b: 42
    }
    console.log(Object.entries(object1)) // [["a","somestring"],["b",42]]
    for (let [key, value] of Object.entries(object1)) {
          console.log(`${key}: ${value}`)
    }
    // "a: somestring"
    // "b: 42"
    
    
  4. padStart():用另一個(gè)字符串填充當(dāng)前字符串(重復(fù)宪睹,如果需要的話),以便產(chǎn)生的字符串達(dá)到給定的長(zhǎng)度蚕钦。填充從當(dāng)前字符串的開始(左側(cè))應(yīng)用的亭病。

    const str1 = '5'
    console.log(str1.padStart(4, '0'))  //  "0005"
    // 若無(wú)第二個(gè)參數(shù),用空格填充
    console.log(str1.padStart(4))  //  "   5"
    
    
  5. padEnd():用一個(gè)字符串填充當(dāng)前字符串(如果需要的話則重復(fù)填充)嘶居,返回填充后達(dá)到指定長(zhǎng)度的字符串罪帖。從當(dāng)前字符串的末尾(右側(cè))開始填充。

    const str1 = 'Breaded Mushrooms'
    console.log(str1.padEnd(25, '.'))  //  "Breaded Mushrooms........"
    const str2 = '200'
    console.log(str2.padEnd(5))  //  "200  "
    
    
  6. 函數(shù)參數(shù)結(jié)尾逗號(hào)

  7. SharedArrayBuffer對(duì)象
    SharedArrayBuffer 對(duì)象用來(lái)表示一個(gè)通用的邮屁,固定長(zhǎng)度的原始二進(jìn)制數(shù)據(jù)緩沖區(qū)胸蛛,類似于 ArrayBuffer 對(duì)象,它們都可以用來(lái)在共享內(nèi)存(shared memory)上創(chuàng)建視圖樱报。與 ArrayBuffer 不同的是葬项,SharedArrayBuffer 不能被分離。

    // 參數(shù)length指所創(chuàng)建的數(shù)組緩沖區(qū)的大小迹蛤,以字節(jié)(byte)為單位
    let sab = new SharedArrayBuffer(1024)  // 創(chuàng)建一個(gè)1024字節(jié)的緩沖
    
    
  8. Atomics對(duì)象
    Atomics對(duì)象 提供了一組靜態(tài)方法用來(lái)對(duì) SharedArrayBuffer 對(duì)象進(jìn)行原子操作民珍。

    • Atomics.add():將指定位置上的數(shù)組元素與給定的值相加,并返回相加前該元素的值盗飒。
    • Atomics.and():將指定位置上的數(shù)組元素與給定的值相與嚷量,并返回與操作前該元素的值。
    • Atomics.compareExchange():如果數(shù)組中指定的元素與給定的值相等逆趣,則將其更新為新的值蝶溶,并返回該元素原先的值。
    • Atomics.exchange():將數(shù)組中指定的元素更新為給定的值,并返回該元素更新前的值抖所。
    • Atomics.load():返回?cái)?shù)組中指定元素的值梨州。
    • Atomics.or():將指定位置上的數(shù)組元素與給定的值相或,并返回或操作前該元素的值田轧。
    • Atomics.store():將數(shù)組中指定的元素設(shè)置為給定的值暴匠,并返回該值。
    • Atomics.sub():將指定位置上的數(shù)組元素與給定的值相減傻粘,并返回相減前該元素的值每窖。
    • Atomics.xor():將指定位置上的數(shù)組元素與給定的值相異或,并返回異或操作前該元素的值弦悉。
    • Atomics.wait():檢測(cè)數(shù)組中某個(gè)指定位置上的值是否仍然是給定值窒典,是則保持掛起直到被喚醒或超時(shí)。返回值為 “ok”稽莉、“not-equal” 或 “time-out”瀑志。調(diào)用時(shí),如果當(dāng)前線程不允許阻塞肩祥,則會(huì)拋出異常(大多數(shù)瀏覽器都不允許在主線程中調(diào)用 wait())后室。
    • Atomics.wake():?jiǎn)拘训却?duì)列中正在數(shù)組指定位置的元素上等待的線程。返回值為成功喚醒的線程數(shù)量混狠。
    • Atomics.isLockFree(size):可以用來(lái)檢測(cè)當(dāng)前系統(tǒng)是否支持硬件級(jí)的原子操作岸霹。對(duì)于指定大小的數(shù)組,如果當(dāng)前系統(tǒng)支持硬件級(jí)的原子操作将饺,則返回 true贡避;否則就意味著對(duì)于該數(shù)組,Atomics 對(duì)象中的各原子操作都只能用鎖來(lái)實(shí)現(xiàn)予弧。此函數(shù)面向的是技術(shù)專家刮吧。
  9. Object.getOwnPropertyDescriptors():用來(lái)獲取一個(gè)對(duì)象的所有自身屬性的描述符

    const obj = {
      foo: 123,
      get bar() { return 'abc' }
    };
    
    Object.getOwnPropertyDescriptors(obj)
    // { foo:
    //    { value: 123,
    //      writable: true,
    //      enumerable: true,
    //      configurable: true },
    //   bar:
    //    { get: [Function: bar],
    //      set: undefined,
    //      enumerable: true,
    //      configurable: true } }
    
    
    • 淺拷貝一個(gè)對(duì)象
      Object.assign() 方法只能拷貝源對(duì)象的可枚舉的自身屬性,同時(shí)拷貝時(shí)無(wú)法拷貝屬性的特性們掖蛤,而且訪問(wèn)器屬性會(huì)被轉(zhuǎn)換成數(shù)據(jù)屬性杀捻,也無(wú)法拷貝源對(duì)象的原型,該方法配合 Object.create() 方法可以實(shí)現(xiàn)上面說(shuō)的這些蚓庭。

      Object.create(
        Object.getPrototypeOf(obj),
        Object.getOwnPropertyDescriptors(obj)
       );
      
      
    • 創(chuàng)建子類
      創(chuàng)建子類的典型方法是定義子類致讥,將其原型設(shè)置為超類的實(shí)例,然后在該實(shí)例上定義屬性器赞。這么寫很不優(yōu)雅垢袱,特別是對(duì)于 getters 和 setter 而言。 相反港柜,您可以使用此代碼設(shè)置原型:

      function superclass() {}
      superclass.prototype = {
        // 在這里定義方法和屬性
      };
      function subclass() {}
      subclass.prototype = Object.create(superclass.prototype, Object.getOwnPropertyDescriptors({
        // 在這里定義方法和屬性
      }));
      
      

ES9(ES2018)

  1. for await…of
    for await...of 語(yǔ)句創(chuàng)建一個(gè)循環(huán)请契,該循環(huán)遍歷異步可迭代對(duì)象以及同步可迭代對(duì)象,包括: 內(nèi)置的 String, Array,類似數(shù)組對(duì)象 (例如 argumentsNodeList)爽锥,TypedArray, Map, Set 和用戶定義的異步/同步迭代器涌韩。其會(huì)調(diào)用自定義迭代鉤子,并為每個(gè)不同屬性的值執(zhí)行語(yǔ)句救恨。

    async function* asyncGenerator() {
      var i = 0
      while (i < 3) {
            yield i++
      }
    }
    
    (async function() {
      for await (num of asyncGenerator()) {
            console.log(num)
      }
    })()
    // 0
    // 1
    // 2
    
    
  2. 模板字符串(Template string)
    ES9 開始贸辈,模板字符串允許嵌套支持常見(jiàn)轉(zhuǎn)義序列释树,移除對(duì) ECMAScript 在帶標(biāo)簽的模版字符串中轉(zhuǎn)義序列的語(yǔ)法限制肠槽。

  3. 正則表達(dá)式 Unicode 轉(zhuǎn)義
    正則表達(dá)式中的 Unicode 轉(zhuǎn)義符允許根據(jù) Unicode 字符屬性匹配 Unicode 字符。 它允許區(qū)分字符類型奢啥,例如大寫和小寫字母秸仙,數(shù)學(xué)符號(hào)和標(biāo)點(diǎn)符號(hào)。

    // 匹配所有數(shù)字
    const regex = /^\p{Number}+$/u;
    regex.test('231???') // true
    regex.test('???') // true
    regex.test('ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ') // true
    
    // 匹配所有空格
    \p{White_Space}
    
    // 匹配各種文字的所有字母桩盲,等同于 Unicode 版的 \w
    [\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]
    
    // 匹配各種文字的所有非字母的字符寂纪,等同于 Unicode 版的 \W
    [^\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]
    
    // 匹配 Emoji
    /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu
    
    // 匹配所有的箭頭字符
    const regexArrows = /^\p{Block=Arrows}+$/u;
    regexArrows.test('←↑→↓?????????????') // true
    
    
  4. 正則表達(dá)式 s/dotAll 模式
    JS 正則增加了一個(gè)新的標(biāo)志 s 用來(lái)表示 dotAll,這可以匹配任意字符赌结。

    const re = /foo.bar/s;  //  等價(jià)于 const re = new RegExp('foo.bar', 's');
    re.test('foo\nbar');    // true
    re.dotAll;      // true
    re.flags;       // "s"
    
    
  5. 具名組匹配

const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj.groups.year; // 1999
const month = matchObj.groups.month; // 12
const day = matchObj.groups.day; // 31

  1. 對(duì)象擴(kuò)展操作符

  2. Promise.prototype.finally()
    finally() 方法會(huì)返回一個(gè) Promise捞蛋,當(dāng) promise 的狀態(tài)變更,不管是變成 rejected 或者 fulfilled柬姚,最終都會(huì)執(zhí)行 finally() 的回調(diào)拟杉。

fetch(url)
    .then((res) => {
      console.log(res)
    })
    .catch((error) => { 
      console.log(error)
    })
    .finally(() => { 
      console.log('結(jié)束')
  })

ES10(ES2019)

  1. 數(shù)組實(shí)例的 flat()
    用于將嵌套的數(shù)組“拉平”,變成一維的數(shù)組量承。該方法返回一個(gè)新數(shù)組搬设,對(duì)原數(shù)據(jù)沒(méi)有影響。參數(shù) depth 表示要提取嵌套數(shù)組的結(jié)構(gòu)深度撕捍,默認(rèn)值為 1拿穴。
console.log([1 ,[2, 3]].flat());  //  [1, 2, 3]

// 指定轉(zhuǎn)換的嵌套層數(shù)
console.log([1, [2, [3, [4, 5]]]].flat(2));  //  [1, 2, 3, [4, 5]]

// 不管嵌套多少層【使用 Infinity 作為深度,展開任意深度的嵌套數(shù)組】
console.log([1, [2, [3, [4, 5]]]].flat(Infinity));  //  [1, 2, 3, 4, 5]

// 自動(dòng)跳過(guò)空位【會(huì)移除數(shù)組中的空項(xiàng)】
console.log([1, [2, , 3]].flat());  //  [1, 2, 3]

// 傳入 <=0 的整數(shù)將返回原數(shù)組忧风,不“拉平”
console.log([1, [2, [3, [4, 5]]]].flat(0));  //  [1, [2, [3, [4, 5]]]]
console.log([1, [2, [3, [4, 5]]]].flat(-10));  //  [1, [2, [3, [4, 5]]]]

  1. 數(shù)組實(shí)例的 flatMap()
    首先使用映射函數(shù)映射每個(gè)元素默色,然后將結(jié)果壓縮成一個(gè)新數(shù)組。它與 map 和連著深度值為1的 flat 幾乎相同狮腿,但 flatMap 通常在合并成一種方法的效率稍微高一些腿宰。
[1, 2, 3, 4].flatMap(x => x * 2);  //  [2, 4, 6, 8]
[1, 2, 3, 4].flatMap(x => [x * 2]);  //  [2, 4, 6, 8]

[1, 2, 3, 4].flatMap(x => [[x * 2]]);  //  [[2], [4], [6], [8]]
[1, 2, 3, 4].map(x => [x * 2]);  //  [[2], [4], [6], [8]]

  1. 字符串實(shí)例的 trimStart() / trimLeft() / trimEnd() / trimRight()
    去除字符首或尾的空格,trimStart()trimEnd() 才是標(biāo)準(zhǔn)方法蚤霞,trimLeft()trimRight() 只是別名

  2. Object.fromEntries()
    把鍵值對(duì)列表轉(zhuǎn)換為一個(gè)對(duì)象酗失,它是 Object.entries() 的反函數(shù)。

const entries = new Map([
  ['foo', 'bar'],
  ['baz', 42]
])
console.log(Object.fromEntries(entries))  //  Object { foo: "bar", baz: 42 }

  1. Symbol.prototype.description
    通過(guò)工廠函數(shù) Symbol() 創(chuàng)建符號(hào)時(shí)昧绣,您可以選擇通過(guò)參數(shù)提供字符串作為描述:
Symbol('desc').toString();  //  "Symbol(desc)"
Symbol('desc').description;  //  "desc"
Symbol('').description;  //  ""
Symbol().description;  //  undefined

//全局 symbols
Symbol.for('foo').toString();  //  "Symbol(foo)"
Symbol.for('foo').description;  //  "foo"

  1. Function.prototype.toString()
    現(xiàn)在返回精確字符规肴,包括空格和注釋

  2. try-catch
    catch 的參數(shù)可省略

ES11(ES2020)

  1. String.prototype.matchAll
    返回一個(gè)包含所有匹配正則表達(dá)式及分組捕獲結(jié)果的迭代器。
var regexp = /t(e)(st(\d?))/g
var str = 'test1test2'

str.match(regexp)  //  ['test1', 'test2']
str.matchAll(regexp)  //  RegExpStringIterator {}
[...str.matchAll(regexp)]  //  [ ['test1', 'e', 'st1', '1', index: 0, input: 'test1test2', length: 4], ['test2', 'e', 'st2', '2', index: 5, input: 'test1test2', length: 4] ]

  1. 動(dòng)態(tài) import()
const modelpath = '/demo'
import(`@/pages${modelpath}`).then(module => {}).catch(err => {})

  1. import.meta
    import.meta 會(huì)返回一個(gè)對(duì)象,有一個(gè) url 屬性拖刃,返回當(dāng)前模塊的 url 路徑删壮,只能在模塊內(nèi)部使用。

  2. export * as XX from 'module'import * as XX from 'module'

  3. Promise.allSettled()
    Promise.allSettled 方法返回一個(gè)在所有給定的 promise 都已經(jīng) fulfilledrejected 后的 promise 兑牡,并帶有一個(gè)對(duì)象數(shù)組央碟,每個(gè)對(duì)象表示對(duì)應(yīng)的 promise 結(jié)果。

  4. BigInt
    現(xiàn)在的基本數(shù)據(jù)類型(值類型)不止5種(ES6之后是六種)了哦均函!加上 BigInt 一共有七種基本數(shù)據(jù)類型亿虽,分別是: String、Number苞也、Boolean洛勉、Null、Undefined如迟、Symbol收毫、BigInt
    BigInt 可以表示任意大的整數(shù)∫罂保可以用在一個(gè)整數(shù)字面量后面加 n 的方式定義一個(gè) BigInt 此再,如:10n,或者調(diào)用函數(shù) BigInt()玲销。

  5. globalThis
    指向全局對(duì)象输拇,瀏覽器下指向 window

  6. 可選鏈操作符(?.)
    info.animal?.reptile?.tortoise

  7. 空值合并操作符(??)
    當(dāng)左側(cè)的操作數(shù)為 null 或者 undefined 時(shí),返回其右側(cè)操作數(shù)痒玩,否則返回左側(cè)操作數(shù)淳附。
    與邏輯或操作符(||)不同,邏輯或操作符會(huì)在左側(cè)操作數(shù)為假值時(shí)返回右側(cè)操作數(shù)蠢古。

const foo = null ?? 'default string';
console.log(foo);  // "default string"

const baz = 0 ?? 42;
console.log(baz);  // 0

ES12(ES2021)(預(yù)計(jì)將在2021年年中發(fā)布)

  1. String.prototype.replaceAll
    replaceAll 返回一個(gè)全新的字符串奴曙,所有符合匹配規(guī)則的字符都將被替換掉,替換規(guī)則可以是字符串或者正則表達(dá)式草讶。
let string = 'I like 前端,I like 前端公蝦米'
console.log(string.replace(/like/g,'love'))  // 'I love 前端,I love 前端公蝦米'
console.log(string.replaceAll('like','love'))  // 'I love 前端,I love 前端公蝦米'

需要注意的是洽糟,replaceAll 在使用正則表達(dá)式的時(shí)候,如果非全局匹配(/g)堕战,則 replaceAll() 會(huì)拋出一個(gè)異常

console.log(string.replaceAll(/like/,'love'))  // TypeError

  1. Promise.any
    當(dāng) Promise 列表中的任意一個(gè) promise 成功 resolve 則返回第一個(gè) resolve 的結(jié)果狀態(tài)坤溃,如果所有的 promisereject,則拋出異常表示所有請(qǐng)求失敗嘱丢。
    Promise.race 一旦某個(gè) promise 觸發(fā)了 resolve 或者 reject薪介,就直接返回了該狀態(tài)結(jié)果,并不在乎其成功或者失敗越驻。

  2. WeakRefs
    當(dāng)我們通過(guò)(const汁政、let道偷、var)創(chuàng)建一個(gè)變量時(shí),垃圾收集器 GC 將永遠(yuǎn)不會(huì)從內(nèi)存中刪除該變量记劈,只要它的引用仍然存在可訪問(wèn)勺鸦。WeakRef 對(duì)象包含對(duì)對(duì)象的弱引用。對(duì)對(duì)象的弱引用是不會(huì)阻止垃圾收集器 GC 恢復(fù)該對(duì)象的引用目木,則 GC 可以在任何時(shí)候刪除它换途。
    WeakRefs 在很多情況下都很有用,比如使用 Map 對(duì)象來(lái)實(shí)現(xiàn)具有很多需要大量?jī)?nèi)存的鍵值緩存刽射,在這種情況下最方便的就是盡快釋放鍵值對(duì)占用的內(nèi)存军拟。
    目前,可以通過(guò) WeakMap() 或者 WeakSet() 來(lái)使用 WeakRefs柄冲。

  3. 邏輯運(yùn)算符和賦值表達(dá)式
    表達(dá)式 a op= b 等同于 a = a op (a = b)

a ||= b
//等價(jià)于
a = a || (a = b)  // 當(dāng)LHS值不存在時(shí)吻谋,將RHS變量賦值給LHS

a &&= b
//等價(jià)于
a = a && (a = b)  // 當(dāng)LHS值存在時(shí)忠蝗,將RHS變量賦值給LHS

a ??= b
//等價(jià)于
a = a ?? (a = b)  // 當(dāng)LHS值為null或者undefined時(shí)现横,將RHS變量賦值給LHS

  1. 數(shù)字分隔符號(hào)
    數(shù)字分隔符,可以在數(shù)字之間創(chuàng)建可視化分隔符阁最,通過(guò) _ 下劃線來(lái)分割數(shù)字戒祠,使數(shù)字更具可讀性
const money = 1_000_000_000
//等價(jià)于
const money = 1000000000

const totalFee = 1000.12_34
//等價(jià)于
const totalFee = 1000.1234

// 該新特性同樣支持在八進(jìn)制數(shù)中使用
const number = 0o123_456
//等價(jià)于
const number = 0o123456

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市速种,隨后出現(xiàn)的幾起案子姜盈,更是在濱河造成了極大的恐慌,老刑警劉巖配阵,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件馏颂,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡棋傍,警方通過(guò)查閱死者的電腦和手機(jī)救拉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)瘫拣,“玉大人亿絮,你說(shuō)我怎么就攤上這事◆镏簦” “怎么了派昧?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)拢切。 經(jīng)常有香客問(wèn)我蒂萎,道長(zhǎng),這世上最難降的妖魔是什么淮椰? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任五慈,我火速辦了婚禮帮毁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘豺撑。我一直安慰自己烈疚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布聪轿。 她就那樣靜靜地躺著爷肝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪陆错。 梳的紋絲不亂的頭發(fā)上灯抛,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音音瓷,去河邊找鬼对嚼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛绳慎,可吹牛的內(nèi)容都是我干的纵竖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼杏愤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼靡砌!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起珊楼,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤通殃,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后厕宗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體画舌,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年已慢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了曲聂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蛇受,死狀恐怖句葵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情兢仰,我是刑警寧澤乍丈,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站把将,受9級(jí)特大地震影響轻专,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜察蹲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一请垛、第九天 我趴在偏房一處隱蔽的房頂上張望催训。 院中可真熱鬧,春花似錦宗收、人聲如沸漫拭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)采驻。三九已至,卻和暖如春匈勋,著一層夾襖步出監(jiān)牢的瞬間礼旅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工洽洁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留痘系,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓饿自,卻偏偏與公主長(zhǎng)得像汰翠,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子璃俗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容