[x, y] = [y, x];
function func() { return [1, 2, 3]; } var [a, b, c] = func();
// 參數是一組無次序的值 function f({x, y, z}) { ... } f({z: 1, y: 2, x: 3});
`var jsonData = { id: 12, name: "sss", data: [867, 5309] }; let { id, name, data: number } = jsonData;`
function move({x = 1, y = 2} = {}) { // 默認值 return [x, y]; } move({x: 3}); // y使用默認值,x:3, y:2
const 聲明一個只讀的常量。const聲明的常量不能從新賦值。編程
常量使用Symbol值最大的好處,就是其餘任何值都不可能有相同的值了
Symbol.for方法能夠從新使用同一個Symbol值。
對象的屬性名如今能夠有兩種類型,一種是原來就有的字符串,另外一種就是新增的Symbol類型json
JavaScript只有indexOf方法,能夠用來肯定一個字符串是否包含在另外一個字符串中。ES6又提供了三種新方法。數組
`var s = 'Hello world!'; s.startsWith('Hello') // true s.endsWith('!') // true s.includes('w') // true`
Array.from方法用於將兩類對象轉爲真正的數組promise
var arr= { '0': 'a', '1': 'b', '2': 'c', length: 3 }; // ES6的寫法 var arr2 = Array.from(arr); // ['a', 'b', 'c']
Array.of方法用於將一組值,轉換爲數組。若是沒有參數,就返回一個空數組。瀏覽器
Array.of(7, 8, 9) // [7,8,9] Array.of(13) // [13] Array.of() // [] Array.of(13).length // 1
箭頭函數this對象指向
普通函數this 的指向服務器
箭頭函數的this指向數據結構
箭頭函數體內的this對象就是定義時所在的對象,而不是使用時所在的對象。app
簡單而言,箭頭函數使用時,不綁定this對象,箭頭函數沒有本身的this,它的this是繼承而來的,默認指向在定義箭頭函數時所處的對象。異步
function foo() { return () => { return () => { return () => { console.log('id:', this.id); }; }; }; } var f = foo.call({id: 1}); // 設置foo的id爲1 var t1 = f.call({id: 2})()(); // id: 1 var t2 = f().call({id: 3})(); // id: 1 var t3 = f()().call({id: 4}); // id: 1
上面代碼之中,只有一個this,就是函數foo的this。因此t一、t二、t3都輸出一樣的結果。async
由於全部的內層函數都是箭頭函數,都沒有本身的this,它們的this其實都是最外層foo函數的this。因此箭頭函數的this指向是建立它所在的對象,不會改變。
箭頭函數有幾個使用注意點:
(1)函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。
(2)不能夠看成構造函數,也就是說,不可使用new命令,不然會拋出一個錯誤。
(3)不可使用arguments對象,該對象在函數體內不存在。若是要用,能夠用Rest參數代替。
(4)不可使用yield命令,所以箭頭函數不能用做Generator函數。
ES6引入rest參數(形式爲「...變量名」),用於獲取函數的多餘參數,這樣就不須要使用arguments對象了。rest參數搭配的變量是一個數組,該變量將多餘的參數放入數組中。
function add(...values) { let sum = 0; for (var num of values) { sum += num; } return sum; } add(4, 5, 6,7) // 22
注意,rest參數以後不能再有其餘參數(即只能是最後一個參數),不然會報錯。函數的length屬性,不包括rest參數。
ES6一共有5種方法能夠遍歷對象的屬性:
for...in循環遍歷對象自身的和繼承的可枚舉屬性(不含Symbol屬性)。
Object.keys返回一個數組,包括對象自身的(不含繼承的)全部可枚舉屬性(不含Symbol屬性)。
Object.getOwnPropertyNames返回一個數組,包含對象自身的全部屬性(不含Symbol屬性,可是包括不可枚舉屬性)。
Object.getOwnPropertySymbols返回一個數組,包含對象自身的全部Symbol屬性。
Reflect.ownKeys返回一個數組,包含對象自身的全部屬性,無論是屬性名是Symbol或字符串,也無論是否可枚舉。
以上的5種方法遍歷對象的屬性,都遵照一樣的屬性遍歷的次序規則。
class關鍵字建立一個類代碼以下:
class Person{ constructor(x, y) { this.x = x; this.y = y; } // 方法之間不加逗號隔開,不然報錯 sum(){ // 方法前面不用加function var sum=this.x+this.y; return sum } }
上面代碼定義了一個「類」,能夠看到裏面有一個constructor方法,這就是構造方法,經過new命令生成對象實例時,自動調用該方法。而this關鍵字則表明實例對象。
構造函數的prototype屬性,在ES6的「類」上面繼續存在。全部的方法仍是在prototype屬性上。
類的方法內部若是含有 this,它默認指向類的實例。
ES6提供了新的數據結構Set。它相似於數組,可是成員的值都是惟一的,沒有重複的值。
var set = new Set([1, 2, 3, 3, 4, 4]); set // Set { 1, 2, 3, 4 }
上面代碼能夠發現,定義的set對象會本身去除重複的值。Set表示數據的類型是Set。
由於Set數據值的惟一性,咱們能夠用它來對數組進行去重。代碼以下
var arr=[1, 2, 2, 3, 4, 4]; // 定義一個數組 var set = new Set(arr); //使用擴展運算符Set結構轉爲數組 var newArr=[...set]; // 或者使用Array.from方法將Set結構轉爲數組 var newArr=Array.from(set); newArr // [1, 2, 3, 4]
Set實例的方法分爲兩大類:操做方法(用於操做數據)和遍歷方法(用於遍歷成員)。
下面先介紹四個操做方法。
var s=new Set(); // 定義s 數據類型爲 Set s.add(1).add(2).add(2); // 使用add方法添加值,重複值不會被添加 s.size // 2 注意2被加入了兩次,可是去重了一個,因此s的成員數是2 s.has(1) // true 使用has方法判斷是否有該值,有因此返回true s.has(2) // true s.has(3) // false 沒有該值返回 false s.delete(2); // 使用delete刪除該值 s.has(2) // false 由於2被上面刪除了,因此沒該值,返回false
Set結構的實例有四個遍歷方法,能夠用於遍歷成員。Set的遍歷順序就是插入順序。
Map數據結構解決了傳統對象只能用字符串看成鍵的侷限性。
Map結構的實例屬性和操做方法以下:
(1)size屬性
size屬性返回Map結構的成員總數。
(2)set(key, value)
set方法設置key所對應的鍵值,而後返回整個Map結構。若是key已經有值,則鍵值會被更新,不然就新生成該鍵。
(3)get(key)
get方法讀取key對應的鍵值,若是找不到key,返回undefined。
(4)has(key)
has方法返回一個布爾值,表示某個鍵是否在Map數據結構中。
(5)delete(key)
delete方法刪除某個鍵,返回true。若是刪除失敗,返回false。
(6)clear()
clear方法清除全部成員,沒有返回值。
使用方法以下:
var map=new Map(); map.set('foo', true); // 設置 map.size; // 1 map.get('foo'); // true map.has('foo') // true map.delete('foo'); // 刪除map對象的foo鍵,刪除後使用has返回false map.clear() // 刪除map對象全部的鍵
Map其餘方法
Map原生提供三個遍歷器生成函數和一個遍歷方法。
遍歷方法和Set的差很少。
數據結構的互相轉換
(1)Map轉爲數組
前面已經提過,Map轉爲數組最方便的方法,就是使用擴展運算符(...)。
[...myMap] // myMap表示Map數據
(2)數組轉爲Map
將數組轉入Map構造函數,就能夠轉爲Map。
new Map(數組)
(3)Map轉爲對象
若是全部Map的鍵都是字符串,它能夠轉爲對象。
// Map轉對象函數 function cMapToObj(strMap) { let obj = Object.create(null); for (let [k,v] of strMap) { obj[k] = v; } return obj; } cMapToObj(myMap)
(4)對象轉爲Map
function objToMap(obj) { let strMap = new Map(); for (let k of Object.keys(obj)) { strMap.set(k, obj[k]); } return strMap; } objToMap(對象)
(5)Map轉爲JSON
Map轉爲JSON要區分兩種狀況。一種狀況是Map的鍵名都是字符串,這時能夠選擇轉爲對象JSON。
JSON.stringify(cMapToObj(myMap)) // cMapToObj是上面定義的函數
另外一種狀況是Map的鍵名有非字符串,這時能夠選擇轉爲數組JSON。
JSON.stringify([...myMap])
(6)JSON轉爲Map
JSON轉爲Map,正常狀況下,全部鍵名都是字符串。
objToMap(JSON.parse( json數據 )) // objToMap是上面定義的函數
Proxy 能夠理解成,在目標對象以前架設一層「攔截」,外界對該對象的訪問,都必須先經過這層攔截,所以提供了一種機制,能夠對外界的訪問進行過濾和改寫。
下面是常見的 Proxy 支持的攔截操做方法。
(1)get(target, propKey, receiver)
攔截對象屬性的讀取,好比proxy.foo和proxy['foo']。
最後一個參數receiver是一個對象,可選,參見下面Reflect.get的部分。
(2)set(target, propKey, value, receiver)
攔截對象屬性的設置,好比proxy.foo = v或proxy['foo'] = v,返回一個布爾值。
(3)has(target, propKey)
攔截propKey in proxy的操做,以及對象的hasOwnProperty方法,返回一個布爾值。
(4)deleteProperty(target, propKey)
攔截delete proxy[propKey]的操做,返回一個布爾值。
(5)apply(target, object, args)
攔截 Proxy 實例做爲函數調用的操做,好比proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
(6)construct(target, args)
攔截 Proxy 實例做爲構造函數調用的操做,好比new proxy(...args)。
get()
get方法用於攔截某個屬性的讀取操做。上文已經有一個例子,下面是另外一個攔截讀取操做的例子。
var person = { name: "jack" }; var proxy = new Proxy(person, { get: function(target, property) { if (property in target) { return target[property]; } else { throw new ReferenceError("Property \"" + property + "\" does not exist."); } } }); proxy.name // "jack" proxy.age // 拋出一個錯誤
上面代碼表示,若是訪問目標對象不存在的屬性,會拋出一個錯誤。若是沒有這個攔截函數,訪問不存在的屬性,只會返回undefined。
set()
set方法用來攔截某個屬性的賦值操做。
let obj = { set: function(obj, prop, value) { if (prop === 'age') { if (!Number.isInteger(value)) { throw new TypeError('錯誤信息:不是整數'); } if (value > 200) { throw new RangeError('錯誤信息:年齡大於200'); } } // 對於age之外的屬性,直接保存 obj[prop] = value; } }; let person = new Proxy({}, obj); person.age = 13; person.age // 13 person.age = 'jack' // age不是整數報錯 person.age = 300 // age大於200報錯
上面代碼中,因爲設置了存值函數set,任何不符合要求的age屬性賦值都會拋出一個錯誤。
ES6創造了一種新的遍歷命令for...of循環。Iterator接口的目的,就是爲全部數據結構提供了一種統一的訪問機制,即for...of循環
Iterator的遍歷過程以下:
return方法的使用場合是,若是for...of循環提早退出(一般是由於出錯,或者有break語句或continue語句),就會調用return方法。若是一個對象在完成遍歷前,須要清理或釋放資源,就能夠部署return方法,注意,return方法必須返回一個對象,這是Generator規格決定的。
數組遍歷語法的比較
for循環
最原始的就是for循環
for(var i=0;i<10;i++){ console.log(i); }
forEach
數組提供內置的forEach方法,缺點是沒法中途跳出forEach循環,break命令或return命令都不能奏效。
myArray.forEach(function (value) { console.log(value); });
for...in
遍歷的是key。
缺點:數組的鍵名是數字,可是for...in循環是以字符串做爲鍵名「0」、「1」、「2」等等。
for...in循環主要是爲遍歷對象而設計的,不適用於遍歷數組。
for (let i of list) { console.log( i ); }
for...of
遍歷的是value。
for ...of 循環相比上面幾種作法,有一些顯著的優勢。
for (var n of list ) { if (n > 1000) break; console.log(n); } var list=[1,3,"a","b",6];
代碼1
for( var i in list){ console.log(i) }
代碼2
for(var i of list){ console.log(i) }
代碼1依次輸出結果的是:0 1 2 3 4
代碼2依次輸出的結果是:1 3 a b 6
Promise是爲了解決多重嵌套回調函數而提出的它不是新的語法功能,而是一種新的寫法,容許將回調函數的嵌套,改爲鏈式調用。從語法上說,Promise是一個對象,從它能夠獲取異步操做的消息。
Promise提供統一的API,各類異步操做均可以用一樣的方法進行處理
Promise有如下兩個特色:
Promise也有一些缺點:
ES6規定,Promise對象是一個構造函數,用來生成Promise實例。
Promise構造函數接受一個函數做爲參數,該函數的兩個參數分別是resolve和reject。它們是兩個函數,由JavaScript引擎提供,不用本身部署。
下面代碼創造了一個Promise實例。
var promise = new Promise(function(resolve, reject) { if (true){ resolve(value); } else { reject(error); } });
resolve函數的做用是,將Promise對象的狀態從「未完成」變爲「成功」(即從Pending變爲Resolved),在異步操做成功時調用並將異步操做的結果,做爲參數傳遞出去。
**reject函數的做用是,將Promise對象的狀態從「未完成」變爲「失敗」(即從Pending變爲Rejected),在異步操做失敗時調用並將異步操做報出的錯誤,做爲參數傳遞出去。
**
then方法
Promise實例具備then方法。
then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)。所以能夠採用鏈式寫法,即then方法後面再調用另外一個then方法。
catch方法
Promise.prototype.catch方法是.then(null, rejection)的別名,用於指定發生錯誤時的回調函數。
`
`getJSON("/posts.json") .then(function(posts) {}) .catch(function(error) {console.log('發生錯誤!', error); });`
`
上面代碼中,getJSON方法返回一個Promise對象,若是該對象狀態變爲Resolved,則會調用then方法指定的回調函數;若是異步操做拋出錯誤,狀態就會變爲Rejected,就會調用catch方法指定的回調函數來處理這個錯誤。另外,then方法指定的回調函數,若是運行中拋出錯誤也會被catch方法捕獲。
p.then((val) => console.log("fulfilled:", val)) .catch((err) => console.log("rejected:", err)); // 等同於 p.then((val) => console.log("fulfilled:", val)) .then(null, (err) => console.log("rejected:", err));
ES6誕生之前,異步編程的方法,常見的有下面四種。
ES6將JavaScript異步編程帶入了一個全新的階段,ES7的Async函數更是提出了異步編程的新解決方案
async函數
ES7提供了async函數,使得異步操做變得更加方便。
async函數是什麼?
async函數就是Generator函數的語法糖。
語法 async function name(param) { statements }
返回值
async 函數返回一個 Promise 對象,可使用 then 方法添加回調函數。
async函數內部return語句返回的值,會成爲then方法回調函數的參數。
async function foo(){ return "這是async函數的返回值"; } console.log(foo()) // Promise { '這是async函數的返回值' } foo().then((args)=>{ // 回調函數是箭頭函數 console.log(args); // 這是async函數的返回值 })
await命令
await操做符用於等待一個 Promise 對象, 它只能在異步函數 async function 內部使用。
await 的返回值
function testAwait (x) { return new Promise(resolve => { setTimeout(() => { resolve(x); }, 2000); }); } async function foo() { var x = await testAwait ("hello world"); console.log(x); } foo (); // hello world
async function f() { return await 123; } f().then(v => console.log(v)) // 123
async函數返回的Promise對象,必須等到內部全部await命令的Promise對象執行完纔會發生狀態改變。也就是說,只有async函數內部的異步操做執行完纔會執行then方法指定的回調函數。
async函數的錯誤處理
若是await後面的異步操做出錯,那麼等同於async函數返回的Promise對象被reject。
async function f() { await new Promise(function (resolve, reject) { throw new Error('出錯了111'); }); } f() .then(v => console.log(v)) .catch(e => console.log(e)) // Error:出錯了111
上面代碼中,async函數f執行後,await後面的Promise對象會拋出一個錯誤對象,致使catch方法的回調函數被調用,它的參數就是拋出的錯誤對象。
防止出錯的方法,把await命令放在try...catch代碼塊中。
async function f() { try { await new Promise(function (resolve, reject) { throw new Error('出錯了'); }); } catch(e) { } return await('hello world'); }
十3、ES6模塊化
ES6 以前,社區制定了一些模塊加載方案,最主要的有 CommonJS 和 AMD 兩種。前者用於服務器,後者用於瀏覽器
ES6 在語言標準的層面上,實現了模塊功能,成爲瀏覽器和服務器通用的模塊解決方案。
模塊功能主要由兩個命令構成:export 和 import。export命令用於規定模塊的對外接口,import命令用於輸入其餘模塊提供的功能。
使用export命令定義了模塊的對外接口之後,其餘 JS 文件就能夠經過import命令加載這個模塊。
注意,import命令具備提高效果,會提高到整個模塊的頭部,首先執行。
一個模塊就是一個獨立的文件。該文件內部的全部變量,外部沒法獲取。
若是你但願外部可以讀取模塊內部的某個變量,就必須使用export關鍵字輸出該變量。