ES6學習筆記(五)【解構賦值,Iterator】

簡介

在很多流行的編程語言裏,都有解構賦值的概念,比如PerlPython

ES6中也加入了類似的賦值語句,比以前的賦值操作更靈活,更快捷

正文

數組的解構賦值很好理解,就是按照對應位置,對變量賦值:

let [a, b, c] = [1, 2, 3]

相當於

let a = 1
let b = 2
let c = 3

支持數組嵌套,也支持等號兩邊結構不同的情況

如果變量對應不上值,這個變量就是undefined,如果一個值對應不到變量,那這個值被忽略

[a, b, c] = [1, 2]
// a,b爲1,2   c由於匹配不到爲undefined
[a, b] = [1, 2, 3]
// a,b爲1,2   3由於沒有變量接收被忽略

基於解構賦值,函數也可以有多個返回值了:

function tuple() {
  return [1, 2]
}

let [first, second] = tuple()

解構賦值允許指定默認值,也允許使用rest參數(...)來接收不確定個數的參數:

let [firstName = "John", lastName = "Doe"] = []

let [a, b, ...rest] = [1, 2, 3, 4, 5]
a    // 1
b    // 2 
rest // [3, 4, 5]

與函數的rest參數一樣,rest後面不允許再有其他參數了

對象的解構賦值與數組類似,只有在屬性名對應相同的情況下,右側屬性的值會被賦值給左側對應屬性的值

let {firstName: name, lastName} = {firstName: "John", lastName: "Doe"}

name      // "John"
lastName  // "Doe"
firstName // Uncaught ReferenceError: firstName is not defined

注意被賦值的是同名屬性的值,這裏是name 而不是firseName

lastName被賦值成功是因爲這是變量的簡潔表示法,忘記了的回去看對象一節

其實數組可以看做屬性名都是自然數的對象:

let {"0": a, "1": b} = {"0": 1, "1": 2}

a     // 1
b     // 2

這樣看起來會更好的理解對象的解構賦值,實際上行爲與數組的解構賦值是一致的

思考

這部分內容希望你都可以手動敲一遍,獨立思考

試着用解構賦值去交換兩個變量的值

如果不使用解構賦值,如何交換兩個變量的值呢?


let [a = 1] = [undefined]

let [b = 1] = [null]

上面代碼中的a, b分別是什麼?試着自己解釋這個結果


let [x = y, y = 1] = []

上面代碼的結果是什麼? 爲什麼?


ES6中新增了一種遍歷語法:for (... of ...) 來支持所有可遍歷的數據結構

for-of 是基於iterator這個通用接口實現的

正文

在ES6以前,我們想遍歷一個數組一般有三種方式:

  • for 循環
  • for ... in 語句
  • Array.prototype.forEach 方法

三種方式都有不同程度的缺陷

for循環寫法繁瑣,需要指定循環次數不超過數組長度,否則就會有對應的報錯

for ... in 語句遍歷出的是鍵值,需要做一些轉換才能拿到數據,而且遍歷是無序的

forEach 方法是個不錯的方式,不過它不能中途使用break跳出循環,也不能return終止外層函數

基於這些缺陷,ES6新增了 for ... of 的語法,用於遍歷數組,對象,字符串,或者是SetMap等數據結構

for ... of 遍歷依賴 iterator 接口,只有部署了 iterator 接口的數據類型纔可以被遍歷

iterator 接口是這些數據結構上的一個屬性:Symbol.iterator,它是一個函數

let iterator = [1, 2, 3][Symbol.iterator]()

iterator    //  Array Iterator {}
iterator.next()
// {value: 1, done: false}
iterator.next()
// {value: 2, done: false}
iterator.next()
// {value: 3, done: false}
iterator.next()
// {value: undefined, done: true}

Symbol.iterator顯然是一個Symbol類型值,在Symbol章節介紹過,必須使用方括號訪問

調用數組上的 Symbol.iterator 方法,即可返回一個iterator遍歷器對象

這個 iterator 對象上只有一個常用方法 next ,每次調用 next 即可返回一個對象

返回的對象有兩個屬性,value :當前遍歷的值, done :是否遍歷完畢

這裏必須說明一下爲什麼這個遍歷器的屬性名是一個很繞的Symbol類型

其實最開始是打算叫做 iterator() 的 ,可是考慮到已有的代碼中,可能已經有人用這個名字命名了一些屬性

ES6如果直接使用這個名字會造成兼容性問題,無奈之下只能使用絕對不可能重複的 [Symbol.iterator]()

for…of 語句會在內部直接調用遍歷對象上的 Symbol.iterator 方法

並且每次循環中自動調用返回值的next方法,然後將next方法返回值的value屬性值賦值給每次的循環變量

for (let a of arr){
  console.log(a)
}
//  1  2  3

正常情況下我們不會手動使用next方法去一個一個的拿到值

而是使用 for … of 方便的遍歷所有具有 Symbol.iterator 屬性的對象

思考

這部分內容希望你都可以手動敲一遍,獨立思考

let map = new Map([
  ['a', '1'],
  ['b', '2']
])

for (let a of map){
  console.log(a)
}

上面代碼的輸出結果會是什麼?

如果想要每次只輸出map中每一項對應的值,應該怎麼改寫?


試着根據上面描述的for ... of實現方法,自己動手實現一個具有for ... of功能的function

接收一個可遍歷對象,並向命令行依次輸出遍歷結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章