1.5萬字歸納ES6所有特性(已更新ES2020)

做者:JowayYoung
倉庫:GithubCodePen
博客:官網掘金思否知乎
公衆號:IQ前端
特別聲明:原創不易,未經受權不得轉載或抄襲,如需轉載可聯繫筆者受權前端

前言

第三次閱讀阮一峯老師的《ES6標準入門》了,之前閱讀時不細心,不少地方都是一目十行。最近此次閱讀都是逐個逐個字來讀,發現不少之前都沒有注意到的知識點,爲了方便記憶和預覽所有ES6特性,因此寫下本文。node

如下提到的《ES6標準入門》統一使用《ES6》這個名稱來代替,而最新的ES6版本也是截止到當前的ES2020
複製代碼

本文的知識點徹底是參考或摘錄《ES6》裏的語句,有部分語句爲了方便理解和記憶,進行了相贊成思的轉義,同時對知識點進行歸類劃分。爲了讓你們能集中精力來記住這些特性,全文一句廢話和題外話都沒有,所有模塊以筆記的形式進行書寫,若是看得不是很慣建議對照《ES6》的內容來學習。git

本文整理出來的筆記都是書中的精華內容,囊括了整個ES6體系的全部特性,很是方便你們從新認識所有ES6特性。半小時的閱讀就可對ES6有一個全面的瞭解,可認爲是一本ES6特性小字典,收藏後可隨時查閱。即便看不完也要拉到本文末尾喔,有個大彩蛋,嘻嘻!es6

ES6縮略

修正

ES6ECMAJavaScript制定的第6個標準版本,相關歷史可查看此章節《ES6-ECMAScript6簡介》github

標準委員會最終決定,標準在每一年6月正式發佈並做爲當年的正式版本,接下來的時間裏就在此版本的基礎上進行改動,直到下一年6月草案就天然變成新一年的版本,這樣一來就無需之前的版本號,只要用年份標記便可。ECMAscript 2015是在2015年6月發佈ES6的第一個版本。以此類推,ECMAscript 2016是ES6的第二個版本、 ECMAscript 2017是ES6的第三個版本。ES6既是一個歷史名詞也是一個泛指,含義是5.1版本之後的JavaScript下一代標準,目前涵蓋了ES2015ES2016ES2017ES2018ES2019ES2020web

因此有些文章上提到的ES7(實質上是ES2016)、ES8(實質上是ES2017)、ES9(實質上是ES2018)、ES10(實質上是ES2019)、ES11(實質上是ES2020),實質上都是一些不規範的概念。從ES1到ES6,每一個標準都是花了好幾年甚至十多年才制定下來,你一個ES6到ES7,ES7到ES8,才用了一年,按照這樣的定義下去,那不是很快就ES20了。用正確的概念來講ES6目前涵蓋了ES2015ES2016ES2017ES2018ES2019ES2020正則表達式

ES6組成

另外,ES6更新的內容主要分爲如下幾點編程

  • 表達式:聲明、解構賦值
  • 內置對象:字符串擴展、數值擴展、對象擴展、數組擴展、函數擴展、正則擴展、Symbol、Set、Map、Proxy、Reflect
  • 語句與運算:Class、Module、Iterator
  • 異步編程:Promise、Generator、Async

ES2015

ES2015

聲明

  • const命令:聲明常量
  • let命令:聲明變量

做用json

  • 做用域
    • 全局做用域
    • 函數做用域function() {}
    • 塊級做用域{}
  • 做用範圍
    • var命令在全局代碼中執行
    • const命令let命令只能在代碼塊中執行
  • 賦值使用
    • const命令聲明常量後必須立馬賦值
    • let命令聲明變量後可立馬賦值或使用時賦值
  • 聲明方法:varconstletfunctionclassimport

重點難點segmentfault

  • 不容許重複聲明
  • 未定義就使用會報錯:const命令let命令不存在變量提高
  • 暫時性死區:在代碼塊內使用const命令let命令聲明變量以前,該變量都不可用

解構賦值

  • 字符串解構const [a, b, c, d, e] = "hello"
  • 數值解構const { toString: s } = 123
  • 布爾解構const { toString: b } = true
  • 對象解構
    • 形式:const { x, y } = { x: 1, y: 2 }
    • 默認:const { x, y = 2 } = { x: 1 }
    • 更名:const { x, y: z } = { x: 1, y: 2 }
  • 數組解構
    • 規則:數據結構具備Iterator接口可採用數組形式的解構賦值
    • 形式:const [x, y] = [1, 2]
    • 默認:const [x, y = 2] = [1]
  • 函數參數解構
    • 數組解構:function Func([x = 0, y = 1]) {}
    • 對象解構:function Func({ x = 0, y = 1 } = {}) {}

應用場景

  • 交換變量值:[x, y] = [y, x]
  • 返回函數多個值:const [x, y, z] = Func()
  • 定義函數參數:Func([1, 2])
  • 提取JSON數據:const { name, version } = packageJson
  • 定義函數參數默認值:function Func({ x = 1, y = 2 } = {}) {}
  • 遍歷Map結構:for (let [k, v] of Map) {}
  • 輸入模塊指定屬性和方法:const { readFile, writeFile } = require("fs")

重點難點

  • 匹配模式:只要等號兩邊的模式相同,左邊的變量就會被賦予對應的值
  • 解構賦值規則:只要等號右邊的值不是對象或數組,就先將其轉爲對象
  • 解構默認值生效條件:屬性值嚴格等於undefined
  • 解構遵循匹配模式
  • 解構不成功時變量的值等於undefined
  • undefinednull沒法轉爲對象,所以沒法進行解構

字符串擴展

  • Unicode表示法大括號包含表示Unicode字符(\u{0xXX}\u{0XXX})
  • 字符串遍歷:可經過for-of遍歷字符串
  • 字符串模板:可單行可多行可插入變量的加強版字符串
  • 標籤模板:函數參數的特殊調用
  • String.raw():返回把字符串全部變量替換且對斜槓進行轉義的結果
  • String.fromCodePoint():返回碼點對應字符
  • codePointAt():返回字符對應碼點(String.fromCodePoint()的逆操做)
  • normalize():把字符的不一樣表示方法統一爲一樣形式,返回新字符串(Unicode正規化)
  • repeat():把字符串重複n次,返回新字符串
  • matchAll():返回正則表達式在字符串的全部匹配
  • includes():是否存在指定字符串
  • startsWith():是否存在字符串頭部指定字符串
  • endsWith():是否存在字符串尾部指定字符串

重點難點

  • 以上擴展方法都可做用於由4個字節儲存Unicode字符

數值擴展

  • 二進制表示法0b或0B開頭表示二進制(0bXX0BXX)
  • 八進制表示法0o或0O開頭表示二進制(0oXX0OXX)
  • Number.EPSILON:數值最小精度
  • Number.MIN_SAFE_INTEGER:最小安全數值(-2^53)
  • Number.MAX_SAFE_INTEGER:最大安全數值(2^53)
  • Number.parseInt():返回轉換值的整數部分
  • Number.parseFloat():返回轉換值的浮點數部分
  • Number.isFinite():是否爲有限數值
  • Number.isNaN():是否爲NaN
  • Number.isInteger():是否爲整數
  • Number.isSafeInteger():是否在數值安全範圍內
  • Math.trunc():返回數值整數部分
  • Math.sign():返回數值類型(正數1負數-1零0)
  • Math.cbrt():返回數值立方根
  • Math.clz32():返回數值的32位無符號整數形式
  • Math.imul():返回兩個數值相乘
  • Math.fround():返回數值的32位單精度浮點數形式
  • Math.hypot():返回全部數值平方和的平方根
  • Math.expm1():返回e^n - 1
  • Math.log1p():返回1 + n的天然對數(Math.log(1 + n))
  • Math.log10():返回以10爲底的n的對數
  • Math.log2():返回以2爲底的n的對數
  • Math.sinh():返回n的雙曲正弦
  • Math.cosh():返回n的雙曲餘弦
  • Math.tanh():返回n的雙曲正切
  • Math.asinh():返回n的反雙曲正弦
  • Math.acosh():返回n的反雙曲餘弦
  • Math.atanh():返回n的反雙曲正切

對象擴展

  • 簡潔表示法:直接寫入變量和函數做爲對象的屬性和方法({ prop, method() {} })
  • 屬性名錶達式:字面量定義對象時使用[]定義鍵([prop],不能與上同時使用)
  • 方法的name屬性:返回方法函數名
    • 取值函數(getter)和存值函數(setter):get/set 函數名(屬性的描述對象在getset上)
    • bind返回的函數:bound 函數名
    • Function構造函數返回的函數實例:anonymous
  • 屬性的可枚舉性和遍歷:描述對象的enumerable
  • super關鍵字:指向當前對象的原型對象(只能用在對象的簡寫方法中method() {})
  • Object.is():對比兩值是否相等
  • Object.assign():合併對象(淺拷貝),返回原對象
  • Object.getPrototypeOf():返回對象的原型對象
  • Object.setPrototypeOf():設置對象的原型對象
  • __proto__:返回或設置對象的原型對象

屬性遍歷

  • 描述:自身可繼承可枚舉非枚舉Symbol
  • 遍歷
    • for-in:遍歷對象自身可繼承可枚舉屬性
    • Object.keys():返回對象自身可枚舉屬性鍵組成的數組
    • Object.getOwnPropertyNames():返回對象自身非Symbol屬性鍵組成的數組
    • Object.getOwnPropertySymbols():返回對象自身Symbol屬性鍵組成的數組
    • Reflect.ownKeys():返回對象自身所有屬性鍵組成的數組
  • 規則
    • 首先遍歷全部數值鍵,按照數值升序排列
    • 其次遍歷全部字符串鍵,按照加入時間升序排列
    • 最後遍歷全部Symbol鍵,按照加入時間升序排列

數組擴展

  • 擴展運算符(...):轉換數組爲用逗號分隔的參數序列([...arr],至關於rest/spread參數的逆運算)
  • Array.from():轉換具備Iterator接口的數據結構爲真正數組,返回新數組
    • 類數組對象:包含length的對象Arguments對象NodeList對象
    • 可遍歷對象:StringSet結構Map結構Generator函數
  • Array.of():轉換一組值爲真正數組,返回新數組
  • copyWithin():把指定位置的成員複製到其餘位置,返回原數組
  • find():返回第一個符合條件的成員
  • findIndex():返回第一個符合條件的成員索引值
  • fill():根據指定值填充整個數組,返回原數組
  • keys():返回以索引值爲遍歷器的對象
  • values():返回以屬性值爲遍歷器的對象
  • entries():返回以索引值和屬性值爲遍歷器的對象
  • 數組空位:ES6明確將數組空位轉爲undefined(空位處理規不一,建議避免出現)

擴展應用

  • 克隆數組:const arr = [...arr1]
  • 合併數組:const arr = [...arr1, ...arr2]
  • 拼接數組:arr.push(...arr1)
  • 代替apply:Math.max.apply(null, [x, y]) => Math.max(...[x, y])
  • 轉換字符串爲數組:[..."hello"]
  • 轉換類數組對象爲數組:[...Arguments, ...NodeList]
  • 轉換可遍歷對象爲數組:[...String, ...Set, ...Map, ...Generator]
  • 與數組解構賦值結合:const [x, ...rest/spread] = [1, 2, 3]
  • 計算Unicode字符長度:Array.from("hello").length => [..."hello"].length

重點難點

  • 使用keys()values()entries()返回的遍歷器對象,可用for-of自動遍歷或next()手動遍歷

函數擴展

  • 參數默認值:爲函數參數指定默認值
    • 形式:function Func(x = 1, y = 2) {}
    • 參數賦值:惰性求值(函數調用後才求值)
    • 參數位置:尾參數
    • 參數做用域:函數做用域
    • 聲明方式:默認聲明,不能用constlet再次聲明
    • length:返回沒有指定默認值的參數個數
    • 與解構賦值默認值結合:function Func({ x = 1, y = 2 } = {}) {}
    • 應用
      • 指定某個參數不得省略,省略即拋出錯誤:function Func(x = throwMissing()) {}
      • 將參數默認值設爲undefined,代表此參數可省略:Func(undefined, 1)
  • rest/spread參數(...):返回函數多餘參數
    • 形式:以數組的形式存在,以後不能再有其餘參數
    • 做用:代替Arguments對象
    • length:返回沒有指定默認值的參數個數但不包括rest/spread參數
  • 嚴格模式:在嚴格條件下運行JS
    • 應用:只要函數參數使用默認值、解構賦值、擴展運算符,那麼函數內部就不能顯式設定爲嚴格模式
  • name屬性:返回函數的函數名
    • 將匿名函數賦值給變量:空字符串(ES5)、變量名(ES6)
    • 將具名函數賦值給變量:函數名(ES5和ES6)
    • bind返回的函數:bound 函數名(ES5和ES6)
    • Function構造函數返回的函數實例:anonymous(ES5和ES6)
  • 箭頭函數(=>):函數簡寫
    • 無參數:() => {}
    • 單個參數:x => {}
    • 多個參數:(x, y) => {}
    • 解構參數:({x, y}) => {}
    • 嵌套使用:部署管道機制
    • this指向固定化
      • 並不是由於內部有綁定this的機制,而是根本沒有本身的this,致使內部的this就是外層代碼塊的this
      • 由於沒有this,所以不能用做構造函數
  • 尾調用優化:只保留內層函數的調用幀
    • 尾調用
      • 定義:某個函數的最後一步是調用另外一個函數
      • 形式:function f(x) { return g(x); }
    • 尾遞歸
      • 定義:函數尾調用自身
      • 做用:只要使用尾遞歸就不會發生棧溢出,相對節省內存
      • 實現:把全部用到的內部變量改寫成函數的參數並使用參數默認值

箭頭函數誤區

  • 函數體內的this定義時所在的對象而不是使用時所在的對象
  • 可以讓this指向固定化,這種特性頗有利於封裝回調函數
  • 不可看成構造函數,所以箭頭函數不可以使用new命令
  • 不可以使用yield命令,所以箭頭函數不能用做Generator函數
  • 不可以使用Arguments對象,此對象在函數體內不存在(可用rest/spread參數代替)
  • 返回對象時必須在對象外面加上括號

正則擴展

  • 變動RegExp構造函數入參:容許首參數爲正則對象,尾參數爲正則修飾符(返回的正則表達式會忽略原正則表達式的修飾符)
  • 正則方法調用變動:字符串對象的match()replace()search()split()內部調用轉爲調用RegExp實例對應的RegExp.prototype[Symbol.方法]
  • u修飾符:Unicode模式修飾符,正確處理大於\uFFFFUnicode字符
    • 點字符(.)
    • Unicode表示法
    • 量詞
    • 預約義模式
    • i修飾符
    • 轉義
  • y修飾符:粘連修飾符,確保匹配必須從剩餘的第一個位置開始全局匹配(與g修飾符做用相似)
  • unicode:是否設置u修飾符
  • sticky:是否設置y修飾符
  • flags:返回正則表達式的修飾符

重點難點

  • y修飾符隱含頭部匹配標誌^
  • 單單一個y修飾符match()只能返回第一個匹配,必須與g修飾符聯用才能返回全部匹配

Symbol

  • 定義:獨一無二的值
  • 聲明:const set = Symbol(str)
  • 入參:字符串(可選)
  • 方法
    • Symbol():建立以參數做爲描述的Symbol值(不登記在全局環境)
    • Symbol.for():建立以參數做爲描述的Symbol值,如存在此參數則返回原有的Symbol值(先搜索後建立,登記在全局環境)
    • Symbol.keyFor():返回已登記的Symbol值的描述(只能返回Symbol.for()key)
    • Object.getOwnPropertySymbols():返回對象中全部用做屬性名的Symbol值的數組
  • 內置
    • Symbol.hasInstance:指向一個內部方法,當其餘對象使用instanceof運算符判斷是否爲此對象的實例時會調用此方法
    • Symbol.isConcatSpreadable:指向一個布爾,定義對象用於Array.prototype.concat()時是否可展開
    • Symbol.species:指向一個構造函數,當實例對象使用自身構造函數時會調用指定的構造函數
    • Symbol.match:指向一個函數,當實例對象被String.prototype.match()調用時會從新定義match()的行爲
    • Symbol.replace:指向一個函數,當實例對象被String.prototype.replace()調用時會從新定義replace()的行爲
    • Symbol.search:指向一個函數,當實例對象被String.prototype.search()調用時會從新定義search()的行爲
    • Symbol.split:指向一個函數,當實例對象被String.prototype.split()調用時會從新定義split()的行爲
    • Symbol.iterator:指向一個默認遍歷器方法,當實例對象執行for-of時會調用指定的默認遍歷器
    • Symbol.toPrimitive:指向一個函數,當實例對象被轉爲原始類型的值時會返回此對象對應的原始類型值
    • Symbol.toStringTag:指向一個函數,當實例對象被Object.prototype.toString()調用時其返回值會出如今toString()返回的字符串之中表示對象的類型
    • Symbol.unscopables:指向一個對象,指定使用with時哪些屬性會被with環境排除

數據類型

  • Undefined
  • Null
  • String
  • Number
  • Boolean
  • Object(包含ArrayFunctionDateRegExpError)
  • Symbol

應用場景

  • 惟一化對象屬性名:屬性名屬於Symbol類型,就都是獨一無二的,可保證不會與其餘屬性名產生衝突
  • 消除魔術字符串:在代碼中屢次出現且與代碼造成強耦合的某一個具體的字符串或數值
  • 遍歷屬性名:沒法經過for-infor-ofObject.keys()Object.getOwnPropertyNames()JSON.stringify()返回,只能經過Object.getOwnPropertySymbols返回
  • 啓用模塊的Singleton模式:調用一個類在任什麼時候候返回同一個實例(windowglobal),使用Symbol.for()來模擬全局的Singleton模式

重點難點

  • Symbol()生成一個原始類型的值不是對象,所以Symbol()前不能使用new命令
  • Symbol()參數表示對當前Symbol值的描述,相同參數的Symbol()返回值不相等
  • Symbol值不能與其餘類型的值進行運算
  • Symbol值可經過String()toString()顯式轉爲字符串
  • Symbol值做爲對象屬性名時,此屬性是公開屬性,但不是私有屬性
  • Symbol值做爲對象屬性名時,只能用方括號運算符([])讀取,不能用點運算符(.)讀取
  • Symbol值做爲對象屬性名時,不會被常規方法遍歷獲得,可利用此特性爲對象定義非私有但又只用於內部的方法

Set

Set
  • 定義:相似於數組的數據結構,成員值都是惟一且沒有重複的值
  • 聲明:const set = new Set(arr)
  • 入參:具備Iterator接口的數據結構
  • 屬性
    • constructor:構造函數,返回Set
    • size:返回實例成員總數
  • 方法
    • add():添加值,返回實例
    • delete():刪除值,返回布爾
    • has():檢查值,返回布爾
    • clear():清除全部成員
    • keys():返回以屬性值爲遍歷器的對象
    • values():返回以屬性值爲遍歷器的對象
    • entries():返回以屬性值和屬性值爲遍歷器的對象
    • forEach():使用回調函數遍歷每一個成員

應用場景

  • 去重字符串:[...new Set(str)].join("")
  • 去重數組:[...new Set(arr)]Array.from(new Set(arr))
  • 集合數組
    • 聲明:const a = new Set(arr1)const b = new Set(arr2)
    • 並集:new Set([...a, ...b])
    • 交集:new Set([...a].filter(v => b.has(v)))
    • 差集:new Set([...a].filter(v => !b.has(v)))
  • 映射集合
    • 聲明:let set = new Set(arr)
    • 映射:set = new Set([...set].map(v => v * 2))set = new Set(Array.from(set, v => v * 2))

重點難點

  • 遍歷順序:插入順序
  • 沒有鍵只有值,可認爲鍵和值兩值相等
  • 添加多個NaN時,只會存在一個NaN
  • 添加相同的對象時,會認爲是不一樣的對象
  • 添加值時不會發生類型轉換(5 !== "5")
  • keys()values()的行爲徹底一致,entries()返回的遍歷器同時包括鍵和值且兩值相等
WeakSet
  • 定義:和Set結構相似,成員值只能是對象
  • 聲明:const set = new WeakSet(arr)
  • 入參:具備Iterator接口的數據結構
  • 屬性
    • constructor:構造函數,返回WeakSet
  • 方法
    • add():添加值,返回實例
    • delete():刪除值,返回布爾
    • has():檢查值,返回布爾

應用場景

  • 儲存DOM節點:DOM節點被移除時自動釋放此成員,不用擔憂這些節點從文檔移除時會引起內存泄漏
  • 臨時存放一組對象或存放跟對象綁定的信息:只要這些對象在外部消失,它在WeakSet結構中的引用就會自動消

重點難點

  • 成員都是弱引用,垃圾回收機制不考慮WeakSet結構對此成員的引用
  • 成員不適合引用,它會隨時消失,所以ES6規定WeakSet結構不可遍歷
  • 其餘對象再也不引用成員時,垃圾回收機制會自動回收此成員所佔用的內存,不考慮此成員是否還存在於WeakSet結構

Map

Map
  • 定義:相似於對象的數據結構,成員鍵是任何類型的值
  • 聲明:const set = new Map(arr)
  • 入參:具備Iterator接口且每一個成員都是一個雙元素數組的數據結構
  • 屬性
    • constructor:構造函數,返回Map
    • size:返回實例成員總數
  • 方法
    • get():返回鍵值對
    • set():添加鍵值對,返回實例
    • delete():刪除鍵值對,返回布爾
    • has():檢查鍵值對,返回布爾
    • clear():清除全部成員
    • keys():返回以鍵爲遍歷器的對象
    • values():返回以值爲遍歷器的對象
    • entries():返回以鍵和值爲遍歷器的對象
    • forEach():使用回調函數遍歷每一個成員

重點難點

  • 遍歷順序:插入順序
  • 對同一個鍵屢次賦值,後面的值將覆蓋前面的值
  • 對同一個對象的引用,被視爲一個鍵
  • 對一樣值的兩個實例,被視爲兩個鍵
  • 鍵跟內存地址綁定,只要內存地址不同就視爲兩個鍵
  • 添加多個以NaN做爲鍵時,只會存在一個以NaN做爲鍵的值
  • Object結構提供字符串—值的對應,Map結構提供值—值的對應
WeakMap
  • 定義:和Map結構相似,成員鍵只能是對象
  • 聲明:const set = new WeakMap(arr)
  • 入參:具備Iterator接口且每一個成員都是一個雙元素數組的數據結構
  • 屬性
    • constructor:構造函數,返回WeakMap
  • 方法
    • get():返回鍵值對
    • set():添加鍵值對,返回實例
    • delete():刪除鍵值對,返回布爾
    • has():檢查鍵值對,返回布爾

應用場景

  • 儲存DOM節點:DOM節點被移除時自動釋放此成員鍵,不用擔憂這些節點從文檔移除時會引起內存泄漏
  • 部署私有屬性:內部屬性是實例的弱引用,刪除實例時它們也隨之消失,不會形成內存泄漏

重點難點

  • 成員鍵都是弱引用,垃圾回收機制不考慮WeakMap結構對此成員鍵的引用
  • 成員鍵不適合引用,它會隨時消失,所以ES6規定WeakMap結構不可遍歷
  • 其餘對象再也不引用成員鍵時,垃圾回收機制會自動回收此成員所佔用的內存,不考慮此成員是否還存在於WeakMap結構
  • 一旦再也不須要,成員會自動消失,不用手動刪除引用
  • 弱引用的只是鍵而不是值,值依然是正常引用
  • 即便在外部消除了成員鍵的引用,內部的成員值依然存在

Proxy

  • 定義:修改某些操做的默認行爲
  • 聲明:const proxy = new Proxy(target, handler)
  • 入參
    • target:攔截的目標對象
    • handler:定製攔截行爲
  • 方法
    • Proxy.revocable():返回可取消的Proxy實例(返回{ proxy, revoke },經過revoke()取消代理)
  • 攔截方式
    • get():攔截對象屬性讀取
    • set():攔截對象屬性設置,返回布爾
    • has():攔截對象屬性檢查k in obj,返回布爾
    • deleteProperty():攔截對象屬性刪除delete obj[k],返回布爾
    • defineProperty():攔截對象屬性定義Object.defineProperty()Object.defineProperties(),返回布爾
    • ownKeys():攔截對象屬性遍歷for-inObject.keys()Object.getOwnPropertyNames()Object.getOwnPropertySymbols(),返回數組
    • getOwnPropertyDescriptor():攔截對象屬性描述讀取Object.getOwnPropertyDescriptor(),返回對象
    • getPrototypeOf():攔截對象原型讀取instanceofObject.getPrototypeOf()Object.prototype.__proto__Object.prototype.isPrototypeOf()Reflect.getPrototypeOf(),返回對象
    • setPrototypeOf():攔截對象原型設置Object.setPrototypeOf(),返回布爾
    • isExtensible():攔截對象是否可擴展讀取Object.isExtensible(),返回布爾
    • preventExtensions():攔截對象不可擴展設置Object.preventExtensions(),返回布爾
    • apply():攔截Proxy實例做爲函數調用proxy()proxy.apply()proxy.call()
    • construct():攔截Proxy實例做爲構造函數調用new proxy()

應用場景

  • Proxy.revocable():不容許直接訪問對象,必須經過代理訪問,一旦訪問結束就收回代理權不容許再次訪問
  • get():讀取未知屬性報錯、讀取數組負數索引的值、封裝鏈式操做、生成DOM嵌套節點
  • set():數據綁定(Vue數據綁定實現原理)、確保屬性值設置符合要求、防止內部屬性被外部讀寫
  • has():隱藏內部屬性不被發現、排除不符合屬性條件的對象
  • deleteProperty():保護內部屬性不被刪除
  • defineProperty():阻止屬性被外部定義
  • ownKeys():保護內部屬性不被遍歷

重點難點

  • 要使Proxy起做用,必須針對實例進行操做,而不是針對目標對象進行操做
  • 沒有設置任何攔截時,等同於直接通向原對象
  • 屬性被定義爲不可讀寫/擴展/配置/枚舉時,使用攔截方法會報錯
  • 代理下的目標對象,內部this指向Proxy代理

Reflect

  • 定義:保持Object方法的默認行爲
  • 方法
    • get():返回對象屬性
    • set():設置對象屬性,返回布爾
    • has():檢查對象屬性,返回布爾
    • deleteProperty():刪除對象屬性,返回布爾
    • defineProperty():定義對象屬性,返回布爾
    • ownKeys():遍歷對象屬性,返回數組(Object.getOwnPropertyNames()+Object.getOwnPropertySymbols())
    • getOwnPropertyDescriptor():返回對象屬性描述,返回對象
    • getPrototypeOf():返回對象原型,返回對象
    • setPrototypeOf():設置對象原型,返回布爾
    • isExtensible():返回對象是否可擴展,返回布爾
    • preventExtensions():設置對象不可擴展,返回布爾
    • apply():綁定this後執行指定函數
    • construct():調用構造函數建立實例

設計目的

  • Object屬於語言內部的方法放到Reflect
  • 將某些Object方法報錯狀況改爲返回false
  • Object操做變成函數行爲
  • ProxyReflect相輔相成

廢棄方法

  • Object.defineProperty() => Reflect.defineProperty()
  • Object.getOwnPropertyDescriptor() => Reflect.getOwnPropertyDescriptor()

重點難點

  • Proxy方法Reflect方法一一對應
  • ProxyReflect聯合使用,前者負責攔截賦值操做,後者負責完成賦值操做

數據綁定:觀察者模式

const observerQueue = new Set();
const observe = fn => observerQueue.add(fn);
const observable = obj => new Proxy(obj, {
    set(tgt, key, val, receiver) {
        const result = Reflect.set(tgt, key, val, receiver);
        observerQueue.forEach(v => v());
        return result;
    }
});

const person = observable({ age: 25, name: "Yajun" });
const print = () => console.log(`${person.name} is ${person.age} years old`);
observe(print);
person.name = "Joway";
複製代碼

Class

  • 定義:對一類具備共同特徵的事物的抽象(構造函數語法糖)
  • 原理:類自己指向構造函數,全部方法定義在prototype上,可看做構造函數的另外一種寫法(Class === Class.prototype.constructor)
  • 方法和關鍵字
    • constructor():構造函數,new命令生成實例時自動調用
    • extends:繼承父類
    • super:新建父類的this
    • static:定義靜態屬性方法
    • get:取值函數,攔截屬性的取值行爲
    • set:存值函數,攔截屬性的存值行爲
  • 屬性
    • __proto__構造函數的繼承(老是指向父類)
    • __proto__.__proto__:子類的原型的原型,即父類的原型(老是指向父類的__proto__)
    • prototype.__proto__屬性方法的繼承(老是指向父類的prototype)
  • 靜態屬性:定義類完成後賦值屬性,該屬性不會被實例繼承,只能經過類來調用
  • 靜態方法:使用static定義方法,該方法不會被實例繼承,只能經過類來調用(方法中的this指向類,而不是實例)
  • 繼承
    • 實質
      • ES5實質:先創造子類實例的this,再將父類的屬性方法添加到this上(Parent.apply(this))
      • ES6實質:先將父類實例的屬性方法加到this上(調用super()),再用子類構造函數修改this
    • super
      • 做爲函數調用:只能在構造函數中調用super(),內部this指向繼承的當前子類(super()調用後纔可在構造函數中使用this)
      • 做爲對象調用:在普通方法中指向父類的原型對象,在靜態方法中指向父類
    • 顯示定義:使用constructor() { super(); }定義繼承父類,沒有書寫則顯示定義
    • 子類繼承父類:子類使用父類的屬性方法時,必須在構造函數中調用super(),不然得不到父類的this
      • 父類靜態屬性方法可被子類繼承
      • 子類繼承父類後,可從super上調用父類靜態屬性方法
  • 實例:類至關於實例的原型,全部在類中定義的屬性方法都會被實例繼承
    • 顯式指定屬性方法:使用this指定到自身上(使用Class.hasOwnProperty()可檢測到)
    • 隱式指定屬性方法:直接聲明定義在對象原型上(使用Class.__proto__.hasOwnProperty()可檢測到)
  • 表達式
    • 類表達式:const Class = class {}
    • name屬性:返回緊跟class後的類名
    • 屬性表達式:[prop]
    • Generator方法:* mothod() {}
    • Async方法:async mothod() {}
  • this指向:解構實例屬性或方法時會報錯
    • 綁定this:this.mothod = this.mothod.bind(this)
    • 箭頭函數:this.mothod = () => this.mothod()
  • 屬性定義位置
    • 定義在構造函數中並使用this指向
    • 定義在類最頂層
  • new.target:肯定構造函數是如何調用

原生構造函數

  • String()
  • Number()
  • Boolean()
  • Array()
  • Object()
  • Function()
  • Date()
  • RegExp()
  • Error()

重點難點

  • 在實例上調用方法,實質是調用原型上的方法
  • Object.assign()可方便地一次向類添加多個方法(Object.assign(Class.prototype, { ... }))
  • 類內部全部定義的方法是不可枚舉的(non-enumerable)
  • 構造函數默認返回實例對象(this),可指定返回另外一個對象
  • 取值函數和存值函數設置在屬性的Descriptor對象
  • 類不存在變量提高
  • 利用new.target === Class寫出不能獨立使用必須繼承後才能使用的類
  • 子類繼承父類後,this指向子類實例,經過super對某個屬性賦值,賦值的屬性會變成子類實例的屬性
  • 使用super時,必須顯式指定是做爲函數仍是做爲對象使用
  • extends不只可繼承類還可繼承原生的構造函數

私有屬性方法

const name = Symbol("name");
const print = Symbol("print");
class Person {
    constructor(age) {
        this[name] = "Bruce";
        this.age = age;
    }
    [print]() {
        console.log(`${this[name]} is ${this.age} years old`);
    }
}
複製代碼

繼承混合類

function CopyProperties(target, source) {
    for (const key of Reflect.ownKeys(source)) {
        if (key !== "constructor" && key !== "prototype" && key !== "name") {
            const desc = Object.getOwnPropertyDescriptor(source, key);
            Object.defineProperty(target, key, desc);
        }
    }
}
function MixClass(...mixins) {
    class Mix {
        constructor() {
            for (const mixin of mixins) {
                CopyProperties(this, new mixin());
            }
        }
    }
    for (const mixin of mixins) {
        CopyProperties(Mix, mixin);
        CopyProperties(Mix.prototype, mixin.prototype);
    }
    return Mix;
}
class Student extends MixClass(Person, Kid) {}
複製代碼

Module

  • 命令
    • export:規定模塊對外接口
      • 默認導出export default Person(導入時可指定模塊任意名稱,無需知曉內部真實名稱)
      • 單獨導出export const name = "Bruce"
      • 按需導出export { age, name, sex }(推薦)
      • 更名導出export { name as newName }
    • import:導入模塊內部功能
      • 默認導入import Person from "person"
      • 總體導入import * as Person from "person"
      • 按需導入import { age, name, sex } from "person"
      • 更名導入import { name as newName } from "person"
      • 自執導入import "person"
      • 複合導入import Person, { name } from "person"
    • 複合模式export命令import命令結合在一塊兒寫成一行,變量實質沒有被導入當前模塊,至關於對外轉發接口,致使當前模塊沒法直接使用其導入變量
      • 默認導入導出export { default } from "person"
      • 總體導入導出export * from "person"
      • 按需導入導出export { age, name, sex } from "person"
      • 更名導入導出export { name as newName } from "person"
      • 具名改默認導入導出export { name as default } from "person"
      • 默認改具名導入導出export { default as name } from "person"
  • 繼承:默認導出更名導出結合使用可以使模塊具有繼承性
  • 設計思想:儘可能地靜態化,使得編譯時就能肯定模塊的依賴關係,以及輸入和輸出的變量
  • 嚴格模式:ES6模塊自動採用嚴格模式(無論模塊頭部是否添加use strict)

模塊方案

  • CommonJS:用於服務器(動態化依賴)
  • AMD:用於瀏覽器(動態化依賴)
  • CMD:用於瀏覽器(動態化依賴)
  • UMD:用於瀏覽器和服務器(動態化依賴)
  • ESM:用於瀏覽器和服務器(靜態化依賴)

加載方式

  • 運行時加載
    • 定義:總體加載模塊生成一個對象,再從對象上獲取須要的屬性和方法進行加載(所有加載)
    • 影響:只有運行時才能獲得這個對象,致使沒法在編譯時作靜態優化
  • 編譯時加載
    • 定義:直接從模塊中獲取須要的屬性和方法進行加載(按需加載)
    • 影響:在編譯時就完成模塊加載,效率比其餘方案高,但沒法引用模塊自己(自己不是對象),可拓展JS高級語法(宏和類型校驗)

加載實現

  • 傳統加載:經過<script>進行同步或異步加載腳本
    • 同步加載:<script src=""></script>
    • Defer異步加載:<script src="" defer></script>(順序加載,渲染完再執行)
    • Async異步加載:<script src="" async></script>(亂序加載,下載完就執行)
  • 模塊加載<script type="module" src=""></script>(默認是Defer異步加載)

CommonJS和ESM的區別

  • CommonJS輸出值的拷貝ESM輸出值的引用
    • CommonJS一旦輸出一個值,模塊內部的變化就影響不到這個值
    • ESM是動態引用且不會緩存值,模塊裏的變量綁定其所在的模塊,等到腳本真正執行時,再根據這個只讀引用到被加載的那個模塊裏去取值
  • CommonJS是運行時加載,ESM是編譯時加載
    • CommonJS加載模塊是對象(即module.exports),該對象只有在腳本運行完纔會生成
    • ESM加載模塊不是對象,它的對外接口只是一種靜態定義,在代碼靜態解析階段就會生成

Node加載

  • 背景:CommonJSESM互不兼容,目前解決方案是將二者分開,採用各自的加載方案
  • 區分:要求ESM採用.mjs後綴文件名
    • require()不能加載.mjs文件,只有import命令纔可加載.mjs文件
    • .mjs文件裏不能使用require(),必須使用import命令加載文件
  • 驅動:node --experimental-modules file.mjs
  • 限制:Node的import命令目前只支持加載本地模塊(file:協議),不支持加載遠程模塊
  • 加載優先級
    • 腳本文件省略後綴名:依次嘗試加載四個後綴名文件(.mjs.js.jsonnode)
    • 以上不存在:嘗試加載package.jsonmain字段指定的腳本
    • 以上不存在:依次嘗試加載名稱爲index四個後綴名文件(.mjs.js.jsonnode)
    • 以上不存在:報錯
  • 不存在的內部變量:argumentsexportsmodulerequirethis__dirname__filename
  • CommonJS加載ESM
    • 不能使用require(),只能使用import()
  • ESM加載CommonJS
    • 自動將module.exports轉化成export default
    • CommonJS輸出緩存機制在ESM加載方式下依然有效
    • 採用import命令加載CommonJS模塊時,不容許採用按需導入,應使用默認導入總體導入

循環加載

  • 定義:腳本A的執行依賴腳本B,而腳本A的執行又依賴腳本B
  • 加載原理
    • CommonJS:require()首次加載腳本就會執行整個腳本,在內存裏生成一個對象緩存下來,二次加載腳本時直接從緩存中獲取
    • ESM:import命令加載變量不會被緩存,而是成爲一個指向被加載模塊的引用
  • 循環加載
    • CommonJS:只輸出已經執行的部分,還未執行的部分不會輸出
    • ESM:需開發者本身保證真正取值時可以取到值(可把變量寫成函數形式,函數具備提高做用)

重點難點

  • ES6模塊中,頂層this指向undefined,不該該在頂層代碼使用this
  • 一個模塊就是一個獨立的文件,該文件內部的全部變量,外部沒法獲取
  • export命令輸出的接口與其對應的值是動態綁定關係,即經過該接口可獲取模塊內部實時的值
  • import命令大括號裏的變量名必須與被導入模塊對外接口的名稱相同
  • import命令輸入的變量只讀(本質是輸入接口),不容許在加載模塊的腳本里改寫接口
  • import命令命令具備提高效果,會提高到整個模塊的頭部,首先執行
  • 重複執行同一句import語句,只會執行一次
  • export default命令只能使用一次
  • export default命令導出的總體模塊,在執行import命令時其後不能跟大括號
  • export default命令本質是輸出一個名爲default的變量,後面不能跟變量聲明語句
  • export default命令本質是將後面的值賦給名爲default的變量,可直接將值寫在其後
  • export default命令export {}命令可同時存在,對應複合導入
  • export命令import命令可出如今模塊任何位置,只要處於模塊頂層便可,不能處於塊級做用域
  • import()加載模塊成功後,此模塊會做爲一個對象,看成then()的參數,可以使用對象解構賦值來獲取輸出接口
  • 同時動態加載多個模塊時,可以使用Promise.all()import()相結合來實現
  • import()和結合async/await來書寫同步操做的代碼

單例模式:跨模塊常量

// 常量跨文件共享
// person.js
const NAME = "Bruce";
const AGE = 25;
const SEX = "male";
export { AGE, NAME, SEX };
複製代碼
// file1.js
import { AGE } from "person";
console.log(AGE);
複製代碼
// file2.js
import { AGE, NAME, SEX } from "person";
console.log(AGE, NAME, SEX);
複製代碼

默認導入互換總體導入

import Person from "person";
console.log(Person.AGE);
複製代碼
import * as Person from "person";
console.log(Person.default.AGE);
複製代碼

Iterator

  • 定義:爲各類不一樣的數據結構提供統一的訪問機制
  • 原理:建立一個指針指向首個成員,按照次序使用next()指向下一個成員,直接到結束位置(數據結構只要部署Iterator接口就可完成遍歷操做)
  • 做用
    • 爲各類數據結構提供一個統一的簡便的訪問接口
    • 使得數據結構成員可以按某種次序排列
    • ES6創造了新的遍歷命令for-ofIterator接口主要供for-of消費
  • 形式:for-of(自動去尋找Iterator接口)
  • 數據結構
    • 集合:ArrayObjectSetMap
    • 原生具有接口的數據結構:StringArraySetMapTypedArrayArgumentsNodeList
  • 部署:默認部署在Symbol.iterator(具有此屬性被認爲可遍歷的iterable)
  • 遍歷器對象
    • next():下一步操做,返回{ done, value }(必須部署)
    • return()for-of提早退出調用,返回{ done: true }
    • throw():不使用,配合Generator函數使用

ForOf循環

  • 定義:調用Iterator接口產生遍歷器對象(for-of內部調用數據結構的Symbol.iterator())
  • 遍歷字符串:for-in獲取索引for-of獲取(可識別32位UTF-16字符)
  • 遍歷數組:for-in獲取索引for-of獲取
  • 遍歷對象:for-in獲取for-of需自行部署
  • 遍歷Set:for-of獲取 => for (const v of set)
  • 遍歷Map:for-of獲取鍵值對 => for (const [k, v] of map)
  • 遍歷類數組:包含length的對象Arguments對象NodeList對象(無Iterator接口的類數組可用Array.from()轉換)
  • 計算生成數據結構:ArraySetMap
    • keys():返回遍歷器對象,遍歷全部的鍵
    • values():返回遍歷器對象,遍歷全部的值
    • entries():返回遍歷器對象,遍歷全部的鍵值對
  • for-in區別
    • 有着同for-in同樣的簡潔語法,但沒有for-in那些缺點、
    • 不一樣於forEach(),它可與breakcontinuereturn配合使用
    • 提供遍歷全部數據結構的統一操做接口

應用場景

  • 改寫具備Iterator接口的數據結構的Symbol.iterator
  • 解構賦值:對Set進行結構
  • 擴展運算符:將部署Iterator接口的數據結構轉爲數組
  • yield*:yield*後跟一個可遍歷的數據結構,會調用其遍歷器接口
  • 接受數組做爲參數的函數:for-ofArray.from()new Set()new WeakSet()new Map()new WeakMap()Promise.all()Promise.race()

Promise

  • 定義:包含異步操做結果的對象
  • 狀態
    • 進行中pending
    • 已成功resolved
    • 已失敗rejected
  • 特色
    • 對象的狀態不受外界影響
    • 一旦狀態改變就不會再變,任什麼時候候均可獲得這個結果
  • 聲明:new Promise((resolve, reject) => {})
  • 出參
    • resolve:將狀態從未完成變爲成功,在異步操做成功時調用,並將異步操做的結果做爲參數傳遞出去
    • reject:將狀態從未完成變爲失敗,在異步操做失敗時調用,並將異步操做的錯誤做爲參數傳遞出去
  • 方法
    • then():分別指定resolved狀態rejected狀態的回調函數
      • 第一參數:狀態變爲resolved時調用
      • 第二參數:狀態變爲rejected時調用(可選)
    • catch():指定發生錯誤時的回調函數
    • Promise.all():將多個實例包裝成一個新實例,返回所有實例狀態變動後的結果數組(齊變動再返回)
      • 入參:具備Iterator接口的數據結構
      • 成功:只有所有實例狀態變成fulfilled,最終狀態纔會變成fulfilled
      • 失敗:其中一個實例狀態變成rejected,最終狀態就會變成rejected
    • Promise.race():將多個實例包裝成一個新實例,返回所有實例狀態優先變動後的結果(先變動先返回)
      • 入參:具備Iterator接口的數據結構
      • 成功失敗:哪一個實例率先改變狀態就返回哪一個實例的狀態
    • Promise.resolve():將對象轉爲Promise對象(等價於new Promise(resolve => resolve()))
      • Promise實例:原封不動地返回入參
      • Thenable對象:將此對象轉爲Promise對象並返回(Thenable爲包含then()的對象,執行then()至關於執行此對象的then())
      • 不具備then()的對象:將此對象轉爲Promise對象並返回,狀態爲resolved
      • 不帶參數:返回Promise對象,狀態爲resolved
    • Promise.reject():將對象轉爲狀態爲rejected的Promise對象(等價於new Promise((resolve, reject) => reject()))

應用場景

  • 加載圖片
  • AJAX轉Promise對象

重點難點

  • 只有異步操做的結果可決定當前狀態是哪種,其餘操做都沒法改變這個狀態
  • 狀態改變只有兩種可能:從pending變爲resolved、從pending變爲rejected
  • 一旦新建Promise對象就會當即執行,沒法中途取消
  • 不設置回調函數,內部拋錯不會反應到外部
  • 當處於pending時,沒法得知目前進展到哪個階段
  • 實例狀態變爲resolvedrejected時,會觸發then()綁定的回調函數
  • resolve()reject()的執行老是晚於本輪循環的同步任務
  • then()返回新實例,其後可再調用另外一個then()
  • then()運行中拋出錯誤會被catch()捕獲
  • reject()的做用等同於拋出錯誤
  • 實例狀態已變成resolved時,再拋出錯誤是無效的,不會被捕獲,等於沒有拋出
  • 實例狀態的錯誤具備冒泡性質,會一直向後傳遞直到被捕獲爲止,錯誤老是會被下一個catch()捕獲
  • 不要在then()裏定義rejected狀態的回調函數(不使用其第二參數)
  • 建議使用catch()捕獲錯誤,不要使用then()第二個參數捕獲
  • 沒有使用catch()捕獲錯誤,實例拋錯不會傳遞到外層代碼,即不會有任何反應
  • 做爲參數的實例定義了catch(),一旦被rejected並不會觸發Promise.all()catch()
  • Promise.reject()的參數會原封不動地做爲rejected的理由,變成後續方法的參數

Generator

  • 定義:封裝多個內部狀態的異步編程解決方案
  • 形式:調用Generator函數(該函數不執行)返回指向內部狀態的指針對象(不是運行結果)
  • 聲明:function* Func() {}
  • 方法
    • next():使指針移向下一個狀態,返回{ done, value }(入參會被看成上一個yield命令表達式的返回值)
    • return():返回指定值且終結遍歷Generator函數,返回{ done: true, value: 入參 }
    • throw():在Generator函數體外拋出錯誤,在Generator函數體內捕獲錯誤,返回自定義的new Errow()
  • yield命令:聲明內部狀態的值(return聲明結束返回的值)
    • 遇到yield命令就暫停執行後面的操做,並將其後表達式的值做爲返回對象的value
    • 下次調用next()時,再繼續往下執行直到遇到下一個yield命令
    • 沒有再遇到yield命令就一直運行到Generator函數結束,直到遇到return語句爲止並將其後表達式的值做爲返回對象的value
    • Generator函數沒有return語句則返回對象的valueundefined
  • yield*命令:在一個Generator函數裏執行另外一個Generator函數(後隨具備Iterator接口的數據結構)
  • 遍歷:經過for-of自動調用next()
  • 做爲對象屬性
    • 全寫:const obj = { method: function*() {} }
    • 簡寫:const obj = { * method() {} }
  • 上下文:執行產生的上下文環境一旦遇到yield命令就會暫時退出堆棧(但並不消失),全部變量和對象會凍結在當前狀態,等到對它執行next()時,這個上下文環境又會從新加入調用棧,凍結的變量和對象恢復執行

方法異同

  • 相同點:next()throw()return()本質上是同一件事,做用都是讓函數恢復執行且使用不一樣的語句替換yield命令
  • 不一樣點
    • next():將yield命令替換成一個
    • return():將yield命令替換成一個return語句
    • throw():將yield命令替換成一個throw語句

應用場景

  • 異步操做同步化表達
  • 控制流管理
  • 爲對象部署Iterator接口:把Generator函數賦值給對象的Symbol.iterator,從而使該對象具備Iterator接口
  • 做爲具備Iterator接口的數據結構

重點難點

  • 每次調用next(),指針就從函數頭部上次停下的位置開始執行,直到遇到下一個yield命令return語句爲止
  • 函數內部可不用yield命令,但會變成單純的暫緩執行函數(仍是須要next()觸發)
  • yield命令是暫停執行的標記,next()是恢復執行的操做
  • yield命令用在另外一個表達式中必須放在圓括號
  • yield命令用做函數參數或放在賦值表達式的右邊,可不加圓括號
  • yield命令自己沒有返回值,可認爲是返回undefined
  • yield命令表達式爲惰性求值,等next()執行到此才求值
  • 函數調用後生成遍歷器對象,此對象的Symbol.iterator是此對象自己
  • 在函數運行的不一樣階段,經過next()從外部向內部注入不一樣的值,從而調整函數行爲
  • 首個next()用來啓動遍歷器對象,後續纔可傳遞參數
  • 想首次調用next()時就能輸入值,可在函數外面再包一層
  • 一旦next()返回對象的donetruefor-of遍歷會停止且不包含該返回對象
  • 函數內部部署try-finally且正在執行try,那麼return()會致使馬上進入finally,執行完finally之後整個函數纔會結束
  • 函數內部沒有部署try-catchthrow()拋錯將被外部try-catch捕獲
  • throw()拋錯要被內部捕獲,前提是必須至少執行過一次next()
  • throw()被捕獲之後,會附帶執行下一條yield命令
  • 函數還未開始執行,這時throw()拋錯只可能拋出在函數外部

首次next()可傳值

function Wrapper(func) {
    return function(...args) {
        const generator = func(...args);
        generator.next();
        return generator;
    }
}
const print = Wrapper(function*() {
    console.log(`First Input: ${yield}`);
    return "done";
});
print().next("hello");
複製代碼

ES2016

ES2016

數值擴展

  • 指數運算符(**):數值求冪(至關於Math.pow())

數組擴展

  • includes():是否存在指定成員

ES2017

ES2017

聲明

  • 共享內存和原子操做:由全局對象SharedArrayBufferAtomics實現,將數據存儲在一塊共享內存空間中,這些數據可在JS主線程web-worker線程之間共享

字符串擴展

  • padStart():把指定字符串填充到字符串頭部,返回新字符串
  • padEnd():把指定字符串填充到字符串尾部,返回新字符串

對象擴展

  • Object.getOwnPropertyDescriptors():返回對象全部自身屬性(非繼承屬性)的描述對象
  • Object.values():返回以值組成的數組
  • Object.entries():返回以鍵和值組成的數組

函數擴展

  • 函數參數尾逗號:容許函數最後一個參數有尾逗號

Async

  • 定義:使異步函數以同步函數的形式書寫(Generator函數語法糖)
  • 原理:將Generator函數和自動執行器spawn包裝在一個函數裏
  • 形式:將Generator函數*替換成async,將yield替換成await
  • 聲明
    • 具名函數:async function Func() {}
    • 函數表達式:const func = async function() {}
    • 箭頭函數:const func = async() => {}
    • 對象方法:const obj = { async func() {} }
    • 類方法:class Cla { async Func() {} }
  • await命令:等待當前Promise對象狀態變動完畢
    • 正常狀況:後面是Promise對象則返回其結果,不然返回對應的值
    • 後隨Thenable對象:將其等同於Promise對象返回其結果
  • 錯誤處理:將await命令Promise對象放到try-catch中(可放多個)

Async對Generator改進

  • 內置執行器
  • 更好的語義
  • 更廣的適用性
  • 返回值是Promise對象

應用場景

  • 按順序完成異步操做

重點難點

  • Async函數返回Promise對象,可以使用then()添加回調函數
  • 內部return返回值會成爲後續then()的出參
  • 內部拋出錯誤會致使返回的Promise對象變爲rejected狀態,被catch()接收到
  • 返回的Promise對象必須等到內部全部await命令Promise對象執行完纔會發生狀態改變,除非遇到return語句拋出錯誤
  • 任何一個await命令Promise對象變爲rejected狀態,整個Async函數都會中斷執行
  • 但願即便前一個異步操做失敗也不要中斷後面的異步操做
    • await命令Promise對象放到try-catch
    • await命令Promise對象跟一個catch()
  • await命令Promise對象可能變爲rejected狀態,最好把其放到try-catch
  • 多個await命令Promise對象若不存在繼發關係,最好讓它們同時觸發
  • await命令只能用在Async函數之中,不然會報錯
  • 數組使用forEach()執行async/await會失效,可以使用for-ofPromise.all()代替
  • 可保留運行堆棧,函數上下文隨着Async函數的執行而存在,執行完成就消失

ES2018

ES2018

字符串擴展

  • 放鬆對標籤模板裏字符串轉義的限制:遇到不合法的字符串轉義返回undefined,而且從raw上可獲取原字符串

對象擴展

  • 擴展運算符(...):轉換對象爲用逗號分隔的參數序列({ ...obj },至關於rest/spread參數的逆運算)

擴展應用

  • 克隆對象:const obj = { __proto__: Object.getPrototypeOf(obj1), ...obj1 }
  • 合併對象:const obj = { ...obj1, ...obj2 }
  • 轉換字符串爲對象:{ ..."hello" }
  • 轉換數組爲對象:{ ...[1, 2] }
  • 與對象解構賦值結合:const { x, ...rest/spread } = { x: 1, y: 2, z: 3 }(不能複製繼承自原型對象的屬性)
  • 修改現有對象部分屬性:const obj = { x: 1, ...{ x: 2 } }

正則擴展

  • s修飾符:dotAll模式修飾符,使.匹配任意單個字符(dotAll模式)
  • dotAll:是否設置s修飾符
  • 後行斷言x只有在y後才匹配
  • 後行否認斷言x只有不在y後才匹配
  • Unicode屬性轉義:匹配符合Unicode某種屬性的全部字符
    • 正向匹配:\p{PropRule}
    • 反向匹配:\P{PropRule}
    • 限制:\p{...}\P{...}只對Unicode字符有效,使用時需加上u修飾符
  • 具名組匹配:爲每組匹配指定名字(?<GroupName>)
    • 形式:str.exec().groups.GroupName
    • 解構賦值替換
      • 聲明:const time = "2017-09-11"const regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u
      • 匹配:time.replace(regexp, "$<day>/$<month>/$<year>")

Promise

  • finally():指定無論最後狀態如何都會執行的回調函數

Async

  • 異步迭代器(for-await-of):循環等待每一個Promise對象變爲resolved狀態才進入下一步

ES2019

ES2019

字符串擴展

  • 直接輸入U+2028和U+2029:字符串可直接輸入行分隔符段分隔符
  • JSON.stringify()改造:可返回不符合UTF-8標準的字符串
  • trimStart():消除字符串頭部空格,返回新字符串
  • trimEnd():消除字符串尾部空格,返回新字符串

對象擴展

  • Object.fromEntries():返回以鍵和值組成的對象(Object.entries()的逆操做)

數組擴展

  • sort()穩定性:排序關鍵字相同的項目其排序先後的順序不變,默認爲穩定
  • flat():扁平化數組,返回新數組
  • flatMap():映射且扁平化數組,返回新數組(只能展開一層數組)

函數擴展

  • toString()改造:返回函數原始代碼(與編碼一致)
  • catch()參數可省略catch()中的參數可省略

Symbol

  • description:返回Symbol值的描述

ES2020

ES2020

聲明

  • globalThis:做爲頂層對象,指向全局環境下的this
    • Browser:頂層對象是window
    • Node:頂層對象是global
    • WebWorker:頂層對象是self
    • 以上三者:通用頂層對象是globalThis

數值擴展

  • BigInt:任何位數的整數(新增的數據類型,使用n結尾)
    • BigInt():轉換普通數值爲BigInt類型
    • BigInt.asUintN():轉換BigInt爲0到2n-1之間對應的值
    • BigInt.asIntN():轉換BigInt爲-2n-1 到2n-1-1
    • BigInt.parseInt():近似於Number.parseInt(),將一個字符串轉換成指定進制的BigInt類型

重點難點

  • BigInt一樣可以使用各類進製表示,都要加上後綴
  • BigInt與普通整數是兩種值,它們之間並不相等
  • typeof運算符對於BigInt類型的數據返回bigint

對象擴展

  • 鏈判斷操做符(?.):是否存在對象屬性(不存在返回undefined且再也不往下執行)
    • 對象屬性:obj?.propobj?.[expr]
    • 函數調用:func?.(...args)
  • 空判斷操做符(??):是否值爲undefinednull,是則使用默認值

正則擴展

  • matchAll():返回全部匹配的遍歷器

Module

  • import():動態導入(返回Promise)
    • 背景:import命令被JS引擎靜態分析,先於模塊內的其餘語句執行,沒法取代require()的動態加載功能,提案建議引入import()來代替require()
    • 位置:可在任何地方使用
    • 區別:require()同步加載import()異步加載
    • 場景:按需加載、條件加載、模塊路徑動態化

Iterator

  • for-in遍歷順序:不一樣的引擎已就如何迭代屬性達成一致,從而使行爲標準化

Promise

  • Promise.allSettled():將多個實例包裝成一個新實例,返回所有實例狀態變動後的狀態數組(齊變動再返回)
    • 入參:具備Iterator接口的數據結構
    • 成功:成員包含statusvaluestatusfulfilledvalue爲返回值
    • 失敗:成員包含statusreasonstatusrejectedvalue爲錯誤緣由

ES提案

ES提案

聲明

  • do表達式:封裝塊級做用域的操做,返回內部最後執行表達式的值(do{})
  • throw表達式:直接使用throw new Error(),無需(){}包括
  • !#命令:指定腳本執行器(寫在文件首行)

數值擴展

  • 數值分隔符(_):使用_做爲千分位分隔符(增長數值的可讀性)
  • Math.signbit():返回數值符號是否設置

函數擴展

  • 函數部分執行:複用函數功能(?表示單個參數佔位符,...表示多個參數佔位符)
  • 管道操做符(|>):把左邊表達式的值傳入右邊的函數進行求值(f(x) => x |> f)
  • 綁定運算符(::):函數綁定(左邊是對象右邊是函數,取代bindapplycall調用)
    • bind:bar.bind(foo) => foo::bar
    • apply:bar.apply(foo, arguments) => foo::bar(...arguments)

Realm

  • 定義:提供沙箱功能,容許隔離代碼,防止被隔離的代碼拿到全局對象
  • 聲明:new Realm().global

Class

  • 靜態屬性:使用static定義屬性,該屬性不會被實例繼承,只能經過類來調用
  • 私有屬性:使用#定義屬性,該屬性只能在類內部訪問
  • 私有方法:使用#定義方法,該方法只能在類內部訪問
  • 裝飾器:使用@註釋或修改類和類方法

Module

  • import.meta:返回腳本元信息

Promise

  • Promise.any():將多個實例包裝成一個新實例,返回所有實例狀態變動後的結果數組(齊變動再返回)
    • 入參:具備Iterator接口的數據結構
    • 成功:其中一個實例狀態變成fulfilled,最終狀態就會變成fulfilled
    • 失敗:只有所有實例狀態變成rejected,最終狀態纔會變成rejected
  • Promise.try():不想區分是否同步異步函數,包裝函數爲實例,使用then()指定下一步流程,使用catch()捕獲錯誤

Async

  • 頂層Await:容許在模塊的頂層獨立使用await命令(借用await解決模塊異步加載的問題)

總結

最後送你們一張完整的ES6特性圖,記得給我點個贊喔,算是對個人一種鼓勵。由於圖片實在太大沒法上傳,請關注IQ前端或掃描文章底部二維碼,後臺回覆ES6,獲取高清的ES6所有特性記憶圖,助你輕鬆記住ES6所有特性

結語

❤️關注+點贊+收藏+評論+轉發❤️,原創不易,鼓勵筆者創做更多高質量文章

關注公衆號IQ前端,一個專一於CSS/JS開發技巧的前端公衆號,更多前端小乾貨等着你喔

  • 關注後回覆資料免費領取學習資料
  • 關注後回覆進羣拉你進技術交流羣
  • 歡迎關注IQ前端,更多CSS/JS開發技巧只在公衆號推送

相關文章
相關標籤/搜索