# JS ES6~11 ###### tags: `JavaScript` ## 1. ES6新特性 ### let關鍵字 let 關键字用來聲明變數,使用let聲明的變數有幾個特點: 1. 不允許重複聲明 2. 區塊(block)級作用域 3. 存在變數提升 4. 不影響作用域鏈 ### const關鍵字 const關鍵字用来聲明常量,const聲明有以下特點 1) 聲明必須赋初始值 2) 變數名通常為大寫(潛規則) 3) 不允許重複聲明 4) 值不允許修改 5) 區塊(block)級作用域 注意:物件屬性修改和陣列元素變化不會觸發const錯誤 應用背景:宣告物件類型使用const,非物件類型聲明選擇let ### 解構賦值 ```javascript= //陣列解構 const arr = ['張學友', '劉德華', '黎明', '郭富城']; let [zhang, liu, li, guo] = arr; //物件的解構賦值 const lin = { name: '林志穎', tags: ['車手', '歌手', '小旋風', '演員'] }; let {name, tags} = lin; //複雜解構 let wangfei = { name: '王菲', age: 18, songs: ['紅豆', '流年', '暧昧', '傳奇'], history: [ {name: '窦唯'}, {name: '李亞鹏'}, {name: '謝霆鋒'} ] }; let {songs: [one, two, three], history: [first, second, third]} = wangfei; ``` ### 模板字串 模板字串(template string)是增強版的字串,用反引號標示,特點: 1) 字串中可以出現換行符號 2) 可以使用 ${xxx} 形式輸出變數 ```javascript= let result = `${date}今天天氣真好`; ``` ### 物件的簡化寫法 ES6 允許在大括號裡面,直接寫入變數和函數,作為物件的屬性和方法。這 樣的書寫更加簡潔。 ```javascript= let name = '馬凱'; let slogon = '永遠追求高標準'; let improve = function () { console.log('可以提高你的技能'); } //屬性和方法簡寫 let atguigu = { name, slogon, improve, change() { console.log('可以改變你') } }; ``` ### 箭頭函數 ES6 允許使用「箭頭」(=>)定義函數。 箭頭函數的注意點: 1. 如果形参只有一個,則小括號可以省略 2. 函數體如果只有一條語句,則花括號可以省略,函數的返回值為該條語句的執行结果 3. 箭頭函数 this 指向宣告時所在作用域下 this 的值 4. 箭頭函数不能作為建構函數實體化 5. 不能使用 arguments ### Rest參數 ES6 導入 rest 参數,用于獲取函数的實参,用來代替 arguments ```javascript= /** * 作用與 arguments 類似 */ function add(...args){ console.log(args); } add(1,2,3,4,5); /** * rest 参數必須是最後一個形参 */ function minus(a,b,...args){ console.log(a,b,args); } minus(100,1,2,3,4,5,19); ``` ### Spread擴展運算符 擴展運算符(spread)也是三個點(...)。它好比 rest 参数的逆運算,將一個陣列轉為用逗號分隔的参數序列,對陣列進行解包。 ```javascript= /** * 展開陣列 */ let tfboys = ['張三','李四','王五']; function fn(){ console.log(arguments); } fn(...tfboys) /** * 展开物件 */ let skillOne = { q: '致命打擊', }; let skillTwo = { w: '勇氣' }; let skillThree = { e: '審判' }; let skillFour = { r: '德瑪西亞之力' }; let gailun = {...skillOne, ...skillTwo,...skillThree,...skillFour}; ``` ### Symbol ES6 導入了一種新的原始數據類型 Symbol,表示獨一無二的值。它是 JavaScript 語言的第七種數據類型,是一種類似於字串的數據類型。 Symbol 特點 1) Symbol 的值是唯一的,用來解决命名衝突的問題 2) Symbol 值不能與其他數據進行運算 3) Symbol 定義的物件屬性不能使用 for…in 循環,但是可以使用Reflect.ownKeys 來獲取物件的所有键名 ```javascript= //建立 Symbol let s1 = Symbol(); console.log(s1, typeof s1); //添加標示的 Symbol let s2 = Symbol('尚硅谷'); let s2_2 = Symbol('尚硅谷'); console.log(s2 === s2_2); //使用 Symbol for 定義 let s3 = Symbol.for('尚硅谷'); let s3_2 = Symbol.for('尚硅谷'); console.log(s3 === s3_2); ``` ### 迭代器 迭代器(Iterator)就是一種機制。它是一種介面,為各種不同的數據結構提 供統一的訪問機制。任何數據結構只要部署 Iterator 介面,就可以完成迭代操作。 1. ES6 創造了一種新的迭代命令 for...of 循環,Iterator 介面主要供 for...of 消費 2. 原生具備 iterator 接口的數據(可用 for of 循環) 1. Array 2. Arguments 3. Set 4. Map 5. String 6. TypedArray 7. NodeList 3. 執行原理 1. 創建一個指標物件,指向當前數據結構的起始位置 2. 第一次調用物件的 next 方法,指針自動指向數據結構的第一個成員 3. 接下来不斷調用 next 方法,指針一直往後移動,直到指向最後一個成員 4. 每調用 next 方法返回一個包含 value 和 done 屬性的物件 注: 需要自定義迭代數據的時候,要想到迭代器。 ### 生成器 生成器函数是 ES6 提供的一種異步编程解决方案,語法行為與傳統函数完全不同 ```javascript= function * gen(){ yield '一隻沒有耳朵'; yield '一隻没有尾巴'; return '真奇怪'; } let iterator = gen(); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); ``` 程式碼說明: 1) *的位置沒有限制 2) 生成器函數返回的结果是迭代器物件,調用迭代器物件的 next 方法可以得到yield 語句後的值 3) yield 相當於函数的暂停標記,也可以認為是函數的分隔符,每調用一次 next方法,執行一段程式碼 4) next 方法可以傳遞實參,作為 yield 語句的返回值 ### Promise Promise 是 ES6 導入的異步编程的新解决方案。語法上 Promise 是一個建構函數,用來封装異步操作並可以獲取其成功或失敗的结果。 1) Promise 建構函數: Promise (excutor) {} 2) Promise.prototype.then 方法 3) Promise.prototype.catch 方法 ```javascript= //實體化Promise物件 const p = new Promise(function(resolve, reject){ setTimeout(function(){ let data = '數據讀取失敗' resolve(data) let err = '數據讀取失敗' reject(err) },1000) }) //調用promise物件的then方法 p.then(function(value){ console.log(value) }, function(reason){ console.error(reason) }) ``` ```javascript= //1.導入fs模組 const fs = require('fs') //2.調用方法讀取文件 fs.readFile('./resources/xxx.md'),(err,data)=>{ //如果失敗,則拋出錯誤 if(err) throw err //如果沒有出錯,則輸出內容 console.log(data.toString()) } //3.使用Promise封裝 const p = new Promise(function(resolve,reject){ fs.readFile("./resources/xxx.md"),(err,data)=>{ //判斷如果失敗 if(err) reject(err) //如果成功 resolve(data) } }) p.then(function(value){ console.log(value.toString()) },function(reson){ console.log("讀取失敗") }) ``` ```javascript= const p = new Promise((resolve, reject) => { //1.創建物件 const xhr = new XMLHttpReuest(); //2.初始化 xhr.open("GET", "https://api.apiopen.top/getJoke") //3.發送 xhr.send() //4.綁定事件,處理回應結果 xhr.onreadystatechange = function(){ //判斷 if(xhr.readyState === 4){ //判斷回應狀態碼 200-299 if(xhr.status >= 200 && xhr.status < 300){ //表示成功 resolve(xhr.response) }else{ //如果失敗 reject(xhr.status) } } } }) //指定回調 p.then(function(value){ console.log(value) },function(reason){ console.error(reason) }) ``` ### Set ES6 提供了新的數據結構 Set(集合)。它類似於陣列,但成員的值都是唯 一的,集合實現了 iterator 接口,所以可以使用『擴展運算符』和『for…of…』進行迭代,集合的屬性和方法: 1. size 返回集合的元素個數 2. add 增加一个新元素,返回當前集合 3. delete 删除元素,返回 boolean 值 4. has 檢測集合中是否包含某個元素,返回 boolean 值 5. clear 清空集合,返回undefined ### Map ES6 提供了 Map 數據結構。它類似於物件,也是鍵值對的集合。但是"鍵"的範圍不限於字串,各種類型的值(包括物件)都可以當作鍵。Map 也實現了iterator 接口,所以可以使用『擴展運算符』和『for…of…』進行迭代。Map 的屬性和方法: 1. size 返回 Map 的元素個數 2. set 增加一個新元素,返回當前 Map 3. get 返回鍵名物件的鍵值 4. has 檢測 Map 中是否包含某個元素,返回 boolean 值 5. clear 清空集合,返回 undefined ```javascript= //創建一個空 map let m = new Map(); //創建一個非空 map let m2 = new Map([ ['name','ykma'], ['slogon','不斷提高標準'] ]) //屬性和方法 //獲取映射元素的個數 console.log(m2.size); //添加映射值 console.log(m2.set('age', 6)); //獲取映射值 console.log(m2.get('age')); //檢測是否有該映射 console.log(m2.has('age')); //清除 console.log(m2.clear()) ``` ### Class類 ES6 提供了更接近傳統语言的寫法,導入了 Class(類)這個概念,作為物件的模板。透過 class 關鍵字,可以定義類。基本上,ES6 的 class 可以看作只是一個語法糖,它的絕大部分功能,ES5 都可以做到,新的 class 寫法只是讓物件原型的寫法更加清晰、更像物件導向的語法而已。 知識點: 1) class 宣告類 2) constructor 定義建構函数初始化 3) extends 繼承父類 4) super 調用父級建構方法 5) static 定義静態方法和屬性 6) 父類方法可以重寫 ```javascript= //父類 class Phone { //建構方法 constructor(brand, color, price) { this.brand = brand; this.color = color; this.price = price; } //物件方法 call(){ console.log('我可以打電話!!!') } } //子類 class SmartPhone extends Phone { constructor(brand, color, price, screen, pixel) { super(brand, color, price); this.screen = screen; this.pixel = pixel; } //子類方法 photo(){ console.log('我可以拍照!!'); } playGame(){ console.log('我可以玩遊戲!!'); } //方法override console.log('我可以進行視訊通話!!'); } //靜態方法 static run(){ console.log('我可以執行程序') } static connect(){ console.log('我可以建立連接') } } ``` ### 數值補充 #### 二進制和八進制 ES6 提供了二進制和八進制數值的新的寫法,分别用前缀 0b 和 0o 表示。 #### Number.isFinite() 與 Number.isNaN() Number.isFinite() 用來檢查一個數值是否為有限的 Number.isNaN() 用來檢查一個值是否為 NaN #### Number.parseInt() 與 Number.parseFloat() ES6 將全域方法 parseInt 和 parseFloat,移植到 Number 物件上面,使用不變。 #### Math.trunc 用於去除一個數的小數部分,返回整數部分。 ### 物件補充 ES6 新增了一些 Object 物件的方法 1. Object.is比較兩個值是否嚴格相等,與『===』行為基本一致(+0 與 NaN) 2. Object.assign 物件的合併,將原物件的所有可枚舉屬性,複製到目標物件 3) __proto__、setPrototypeOf、 setPrototypeOf 可以直接設定物件的原型 ### 模組化 模組化是指將一個大的程序文件,拆分成許多小的文件,然后將小文件组合起來。 好處: 1. 防止命名衝突 2. 程式碼複用 3. 高維護性 ES6之前的模組化規範有: 1. CommonJS => NodeJS、Browserify 2. AMD => requireJS 3. CMD => seaJS ES6模組化語法: 模組功能主要由兩個指令構成:export 和 import。 * export 指令用於規定模組的對外接口 * import 指令用於輸入其他模組提供的功能 ```javascript= //1.通用的導入方式 //導入m1.js模組內容 import * as m1 from "./src/js/m1.js" //2.解構賦值形式 import {school, teach} from "./src/js/m1.js" import {school as nchu, fidJob} from "./src/js/m2.js" import {default as m3} from "./src/js/m3.js" //3.簡單形式(針對預設暴露) import m3 from "./src/js/m3.js" ``` ## 2. ES7新特性 ### Array.prototype.includes Includes 方法用來檢測陣列中是否包含某個元素,返回布林類型值 ``` Array.includes('xxx') ``` ### 指數操作符 在 ES7 中導入指数運算符「**」,用來實現幂運算,功能與 Math.pow 结果相同 ## 3. ES8新特性 ### async 和 await async 和 await 兩種語法结合可以讓異步程式碼像同步程式碼一樣 #### async 函數 1. async 函數的返回值為 promise 物件, 2. promise 物件的结果由 async 函數執行的返回值來決定 ```javascript= //async函數 async function fn(){ //返回一個字串 //return 'ykma' //返回的結果不是一個Promise類型的物件,返回的結果就是成功Promise物件 //拋出錯誤,返回的結果是一個失敗的Promise //throw new Error('出錯啦') //返回的結果如果是一個Promise物件 return new Promise((resolve, reject) => { resolve('成功的數據') //reject('失敗的錯誤') }) } const result = fn() //調用then方法 result.then(value => { console.log(value) }, reason => { console.log(reason) }) ``` #### await 表達式 1. await 必須寫在 async 函數中 2. await 右測的表達示一般為 promise 物件 3. await 返回的是 promise 成功的值 4. await 的 promise 失敗了, 就会抛出異常, 需要透過 try...catch 捕獲處理 ### 物件的補充 #### Object.values() 和 Object.entries() 1. Object.values()方法返回一個给定物件的所有value值的陣列 2. Object.entries()方法返回一個给定物件的[key,value] 陣列(方便建立Map) ```javascript= const school = { name:"ykma", cities:['台中','桃園'] } //獲取物件所有的鍵 console.log(Object.keys(school)) //獲取物件所有的值 console.log(Object.values(school)) //entries //console.log(Object.entries(school)) //創建Map const m = new Map(Object.entries(school)) console.log(m) ``` #### Object.getOwnPropertyDescriptors() 該方法返回指定物件所有自身屬性的描述物件(獲取物件的描述)