本次的ES6語法的彙總總共分爲上、中、下三篇,本篇文章爲中篇。javascript
彙總上篇文章請戳這裏--談談ES6語法(彙總上篇)java
好了,咱們直奔中篇的內容~git
數組擴展運算符(spread)是三個點(...
)。它比如rest參數的逆運算,將一個數組轉爲用空格分隔的參數序列。es6
console.log(...[1, 2, 3]); // 1 2 3
console.log(1, ...[2, 3, 4], 5); // 1 2 3 4 5
複製代碼
⚠️rest參數是運用在函數參數上的,將函數參數轉換爲數組的形式,以下:github
function fn(...values) {
console.log(values); // ['jia', 'ming']
}
fn('jia', 'ming');
複製代碼
下面咱們結合數組擴展運算符和rest參數來實現一個相似call
的方法call2操做:編程
Function.prototype.call2 = function(context, ...args){ // 這裏使用到rest參數
context = context || window; // 由於傳遞過來的context有多是null
context.fn = this; // 讓fn的上下文爲context
const result = context.fn(...args); // 這裏使用了數組擴展運算符
delete context.fn;
return result; // 由於有可能this函數會有返回值return
}
var job = 'outter teacher';
var obj = {
job: 'inner teacher'
};
function showJob() {
console.log(this.job);
}
showJob(); // outter teacher
showJob.call2(obj); // inner teacher
複製代碼
複習一下,咱們把var job = 'outter teacher'
改成let job = 'outter teacher'
後,showJob()
會輸出什麼?json
答案是undefined
。在前一篇中也提到過,ES6語法聲明的變量是不會掛載在全局對象上的~數組
Array.from
方法用於將兩類對象
轉爲真正的數組:相似數組的對象(array-like object)和可遍歷(iterable)的對象(對象包括ES6新增的數據結構Set和Map)。promise
// 類數組轉化成數組
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
}
// ES5的寫法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6的寫法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
複製代碼
Array.of()
方法用於將一組值,轉換爲數組。數據結構
let arr = Array.of(2, 3, 'reng');
console.log(arr); // [2, 3, 'reng']
console.log(arr.pop()); // reng
複製代碼
Array.of
基本上能夠彌補Array()或new Array()
帶來的由於參數個數致使的不一樣行爲。Array.of
基本上能夠替代它們兩個了。
Array.of(); // []
Array.of('reng'); // ['reng']
Array.of(2, 'reng'); // [2, 'reng']
複製代碼
數組中還有其它有用的方法:
include(el)
方法類似[1, [2, [3]]].flat(Infinity);
// [1, 2, 3]
複製代碼
有這麼一個需求:將數組[[2, 8], [2], [[4, 6], 7, 6]]轉成一維且元素不重複的數組。
咱們的實現方案以下:
let arr = [[2, 8], [2], [[4, 6], 7, 6]];
console.log([...new Set(arr.flat(Infinity))]); // [2, 8, 4, 6, 7]
複製代碼
ES6容許字面量定義對象時,把表達式放在方括號內:
let lastWord = 'last word';
const a = {
'first word': 'hello',
[lastWord]: 'world',
['end'+'symbol']: '!'
};
a['first word'] // 'hello'
a[lastWord] // 'world'
a['last word'] // 'world'
a['endsymbol'] // '!'
複製代碼
上面整理數組擴展內容的時候,提到了數組的擴展運算符。ES2018
將這個運算符引入了對象~
let z = { a: 3, b: 4 };
let n = { ...z }; // 關鍵點
n // { a: 3, b: 4 }
複製代碼
===
行爲基本一致const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
複製代碼
Set
翻譯出來就是集合,有元素惟一性的特色。
在數組去重的場景上頗有用處:
// 去除數組的重複成員
[...new Set(array)]
// 如
console.log([...new Set([2, 2, 3, 2])]); // [2, 3]
複製代碼
須要留意的Set屬性和方法有如下:
WeakSet
結構與Set
相似,也是有不重複元素的集合。可是它和Set有兩個區別:
WeakSet
對象中只能存放對象引用, 不能存放值, 而Set
對象均可以.
WeakSet中
對象中存儲的對象值都是被弱引用的, 若是沒有其餘的變量或屬性引用這個對象值, 則這個對象值會被當成垃圾回收掉. 正由於這樣, WeakSet 對象是沒法被枚舉的, 沒有辦法拿到它包含的全部元素。
var ws = new WeakSet();
var obj = {};
var foo = {};
ws.add(window);
ws.add(obj);
ws.has(window); // true
ws.has(foo); // false, 對象 foo 並無被添加進 ws 中
ws.delete(window); // 從集合中刪除 window 對象
ws.has(window); // false, window 對象已經被刪除了
ws.clear(); // 清空整個 WeakSet 對象
複製代碼
WeakSet 沒有size屬性,沒有辦法遍歷它的成員。
Map
對象保持鍵值對。任何值(對象或者原始值)均可以做爲一個鍵或一個值。
Object和Map的比較:
Object
的鍵只能是字符串或者Symbols
,但一個Map
的鍵能夠是任意值,包括函數、對象、基本類型。Map
中的鍵值是有序的,而添加到對象中的鍵則不是。所以,當對它進行遍歷時,Map
對象是按插入的順序返回鍵值。Map
在涉及頻繁增刪鍵值對的場景下會有些性能優點`。若是你須要「鍵值對」的數據結構,Map
比Object
更合適。
const set = new Set([ // 數組轉換爲map
['foo', 1],
['bar', 2]
]);
const m1 = new Map(set);
m1.get('foo') // 1
const m2 = new Map([['baz', 3]]);
const m3 = new Map(m2);
m3.get('baz') // 3
複製代碼
Map擁有的屬性和方法和Set類似,多出了些:
WeakMap
結構與Map
結構相似,也是用於生成鍵值對的集合。可是有兩點區別:
WeakMap
只接受對象做爲鍵名(null除外),不接受其餘類型的值做爲鍵名。WeakMap
的鍵名所指向的對象,不計入垃圾回收機制。和WeakSet
類似啦。屬性方法啥的跟Map
差很少,就是沒有了size
和forEach
,由於其是不可枚舉的。
Promise
是異步編程的一種解決方案,比傳統的解決方案「回調函數和事件」更合理和更強大。
Promise
對象有如下兩個特色:
對象的狀態不受外界影響。Promise
對象表明一個異步操做,有三種狀態:pending
(進行中)、fulfilled
(已成功)和rejected
(已失敗)。
一旦狀態改變,就不會再變,任什麼時候候均可以獲得這個結果。Promise
對象的狀態改變,只有兩種狀況:從pending
變成fulfilled(fulfilled也稱resolved)
和從pending
變成rejected
。
const promise = new Promise(function(resolve, reject) {
// ...some code
if(/* 異步操做成功 */) {
resolve(value);
} else {
reject(error);
}
})
複製代碼
參數resolve
和reject
是兩個函數,由JavaScript引擎提供,不用本身部署。
Promise
實例生成以後,可使用then
方法分別指定resolved
狀態和rejected
狀態的回調函數。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
複製代碼
咱們來粘貼個簡單例子:
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'done');
});
}
timeout(100).then((value) => {
console.log(value); // 100ms後輸出'done'
});
複製代碼
嗯~咱們順道來複習下setTimeout
的第三個參數。哦😯,不,是第三個,第四個...
var timeoutID = scope.setTimeout(function[, delay, param1, param2, ...]);
複製代碼
function
是你想要在到期時間(delay
毫秒)以後執行的函數。delay
是可選語法,表示延遲的毫秒數。param1, ..., paramN
是可選的附加參數,一旦定時器到期,它們會做爲參數傳遞給function
那麼,到這裏你理解了上面的例子爲何在100ms
後輸出done
了嘛💨
詳細的setTimeout
信息,請戳MDN的setTimeout。
簡單的例子看完了,看下咱們在工做中使用得比較多的請求接口的例子:
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if(this.readyState !== 4) {
return;
}
if(this.status === 200) {
resolve(this.response); // this.response做爲參數傳給then中的json
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open('GET', url);
client.onreadystatechange = handler;
client.responseType = 'json';
client.setRequestHeader('Accept', 'application.json');
client.send();
});
return promise;
};
getJSON('/post.json').then(function(json) {
console.log('Contents: '+ json);
}, function(error) {
console.log('error happen ', error);
});
複製代碼
Promise.prototype.catch
方法是.then(null, rejection)
或.then(undefined, rejection)
的別名,用於指定發生錯誤時的回調函數。
p.then((val) => console.log('fulfilled:', val))
.catch((err) => console.log('rejected', err)); // promise中任何一個拋出錯誤,都會被最後一個catch捕獲
// 等同於
p.then((val) => console.log('fulfilled:', val))
.then(null, (err) => console.log('rejected:', err));
複製代碼
Promise.prototype.finally()
方法(其不接受任何參數)用於指定無論Promise
對象最後狀態如何,都會執行的操做。該方法是 ES2018 引入標準的。
語法:
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
複製代碼
構造函數方法Promise.all
方法用於將多個Promise
實例,包裝成一個新的Promise
實例。
const p = Promise.all([p1, p2, p3]);
複製代碼
上面代碼中,Promise.all
方法接受一個數組做爲參數,p1, p2, p3
都是Promise
實例。若是不是會調用Promise.resolve
方法,具體看文檔。
// 生成一個Promise對象的數組
const promises = [2, 3, 5, 7, 11, 13].map(function (id) {
return getJSON('/post/' + id + ".json");
});
Promise.all(promises).then(function (posts) {
// ...
}).catch(function(reason){
// ...
});
複製代碼
上面代碼中,promises
是包含 6 個 Promise
實例的數組,只有這6個實例的狀態都變成fulfilled
,或者其中有一個變爲rejected
,纔會調用Promise.all
方法後面的回調函數。
⚠️注意,若是做爲參數的Promise
實例,本身定義了catch
方法,那麼它一旦被rejected
,並不會觸發Promise.all()
的catch
方法。因此使用Promise.all()
別手癢在每一個實例promise內添加錯誤捕獲。
需求:使用promise改寫下面的代碼,使得輸出的指望結果是每隔一秒輸出0, 1, 2, 3, 4, 5
,其中i < 5
條件不能變
for(var i = 0 ; i < 5; i++){
setTimeout(function(){
console.log(i);
},1000)
}
console.log(i);
複製代碼
咱們直接上使用promise改寫的代碼吧~
const tasks = []; // 存放promise對象
for(let i = 0; i < 5; i++){
tasks.push(new Promise((resolve) => {
setTimeout(() => {
console.log(i);
resolve();
}, 1000 * i);
}));
}
Promise.all(tasks).then(() => {
setTimeout(() => {
console.log(tasks.length);
}, 1000);
});
// 每隔一秒輸出 0, 1, 2, 3, 4, 5
複製代碼
本次的ES6語法的彙總總共分爲上、中、下三篇,本篇文章爲中篇。
文章首發在github上--談談ES6語法(彙總中篇)。更多的內容,請戳個人博客進行了解,能留個star就更好了💨