淺談ES6中迭代器和生成器

淺談ES6中迭代器和生成器


文章首發


本文已經默認你已經知道generator是什麼以及for...of和數據類型map怎麼用了。

前ES6的時代怎麼遍歷

先來一道思考題:

通過下面的變量1. 尋找xiaohong(假設名稱唯一)是否喜歡basketball 2. 所有同學的名字

conststudents={xiaohong:{age:'22',fav:['sleep','basketball'],teachers:{english:'daming',chinense:'helios',math:['helios2','helios3']}},xiaoming:{age:'22',fav:['sleep','basketball','football'],teachers:{english:'daming',chinense:'helios',math:['helios2','helios3']}},}

對於第一個問題來說,我們可以使用各種循環語句: for/while

for(leti=0;i<students[xiaoming].fav.length;i++){if(students[xiaoming].fav[i]==='basketball')console.log(true)}leti=0;while(i++<students[xiaoming].fav.length){if(students[xiaoming].fav[i]==='basketball')console.log(true)}

for...of

for(letitemofstudents[xiaoming].fav){if(item==='basketball')console.log(true)}

那麼對於第二個問題來說,因為for/while是不能遍歷對象的,所以行不通,但是對像有一個專屬的遍歷方法for...in

我們來看一下怎麼通過for...in來遍歷:

for(letstuinstudents){console.log(stu)}

你可能會想了,通過for...in去遍歷數組會怎樣呢?我們看一下通過for...in去遍歷:

for(letiteminstudents[xiaoming].fav){console.log(item)// 或者去判断
}

哎呀,通過for...in不也照樣能實現數組的遍歷麼,那為什麼不歸結到數組的遍歷裡面去呢!這裡面還有一些細節需要去了解(這也是上面的“對像有一個專屬的遍歷方法”為什麼加粗),我們通過一段代碼去解釋:

const num = [ 5 , 6 , 7 ] for ( let i in num ) { console . log ( i + 1 )} // 01 // 11 // 21

這是因為for-in是為普通對象({key: value})設計的,所以只能遍歷到字符串類型的鍵。

還有下面這個雖然不常用,但是也是不得不說的:

const arr = [ 5 , 6 , 7 ] arr . foo = function () {} for ( let i in arr ) { console . log ( i ) } // 5 // 6 // 7 // foo !!!

foo屬於arr上面的方法,被遍歷出來是說的過去的。

那麼用for...of我們來看看會怎麼樣

for(letstuofstudents){}// Uncaught TypeError: students is not iterable

is not iterable ,這個iterable是神馬東西,我們接下來下面一步步的看。

先從可迭代(iterable)和迭代器(iterator)說起

iterable是ES6對iteration(迭代/遍歷)引入的接口。

如果一個對像被視為iterable(可迭代)那麼它一定有一個Symbol.iterator屬性,這個屬性返回一個iterator(迭代器)方法,這個方法返回一個規定的對象(這個後面會說)。也就是說iterableiterator的工廠, iterable能夠創建iteratoriterator是用於遍歷數據結構中元素的指針。

兩者之間的關係

Axel Rauschmaye大神的圖簡直不能再清晰了。

數據消費者: javascript本身提供的消費語句結構,例如for...of循環和spread operator (...)數據源:數據消費者能夠通過不同的源(Array,string)得到供數據消費者消費的值;

數據消費者支持所有的數據源這是不可以行的,因為還可能增加新的數據消費者數據源。因此ES6引入了Iterable接口數據源去實現,數據消費者去使用

可迭代協議(iterable protocol)和迭代器協議(iterator protocol)

可迭代協議(iterable protocol)

可迭代協議(iterable protocol)是允許js對象能夠自定義自己的迭代行為。

簡單的說只要對像有Symbol.iterator這個屬性就是可迭代的,我們可以通過重寫(一些對象實現了iterable,比如Array,string)/添加(對於沒有實現iterable的對像比如object,可以添加這個屬性,使之變為可迭代的)該熟悉使之變為可迭代的。

當一個對象需要被迭代(for...of或者spread operator )的時候,他的Symbol.iterator函數被調用並且無參數,然後返回一個迭代器。

迭代器協議(iterator protocol)

迭代器協議定義了一種標準的方式來產生一個有限或無限序列的值。

當一個對像被認為是一個迭代器的時候,它會至少實現next()方法, next()方法返回兩個屬性value (d迭代器返回的值)和done (迭代時候已經結束)。

還有幾個可選的方法可以被實現,具體請看: sec-iterator-interface

iterable協議iterator協議還有next之間的關係

來源於網絡

然後談談ES6中的for...of說起

再文章的最開始我們已經說了再前ES6的時候,如何去遍歷。現在我們說說ES6新增的for...of的作用。

for...in

在前面也已經說了,在ES6之前遍歷object的時候用for...in循環, for...in會遍歷對像上所有可枚舉的值(包括原型(prototype)上的屬性),比如下面這樣:

function foo () { this . name = 'helios' } foo . prototype . sayName = function () { return this . name ; } var o = new foo (); for ( var i in o ) { console . log ( i ) } // name // sayName

如果我們只想遍歷對象自身的屬性,可以使用hasOwnProperty ,如下:

function foo() { this.name = 'helios' } foo.prototype.sayName = function() { return this.name; } var o = new foo(); for (var i in o) { if (!o.hasOwnProperty(i)) continue; console.log(i) }

如果我們不想讓一個對象的屬性,在for...in中不被遍歷出來,可是使用Object.defineProperty來定義對像上的屬性是否可別枚舉(更多的屬性請看: Object.defineProperty() ),具體如下面代碼:

varobj={name:'helios'}Object.defineProperty(obj,'age',{enumerable:false})for(variinobj){console.log(i)}

在這一小節的最後我們來說說for...in中的in操作符的含義:

prop in obj : -含義:判斷prop是否在obj中- prop:對象的key屬性的類型(string / Symbol) -返回值: boolean

我們來看一組例子:

var o = { name : 'heliso' } console . log ( 'name' in o ) // true console . log ( Symbol . iterator in o ) // false console . log ( 'toString' in o ) // true

這個操作符雖然也適用於數組,但是盡量還是不要用在數組中,因為會比較奇怪,如下代碼:

var arr = [ 6 , 7 , 8 ] console . log ( 7 in arr ) // false console . log ( 1 in arr ) // true console . log ( 'length' in arr ) // true

主要是前兩個比較奇怪對不對,因為對於數組prop代表的是數組的索引而為其存在的值。按照這樣的思路,正在看的讀者你能思考一下in操作符在字符串中是怎麼的模式麼?

for...of能遍歷的集合

只要是實現了Interable接口的數據類型都能被遍歷。

javascript內部實現的有: - Array - String - Map - Set - arguments - DOM data structures

並不是所有的iterable內容都來源於數據結構,也能通過在運行中計算出來,例如所有ES6的主要數據結構有三個方法能夠返回iterable對象。

  • entries() 返回一個可遍歷的entries
  • keys() 返回一個可遍歷的entries 的keys。
  • values() 返回一個可遍歷的entries 的values。

如果for...of不能遍歷怎麼辦

那就數據結構(數據源)去實現iterable就可以了。

用通俗的話說就是,你如果要遍歷一個對象的話,有一下幾個步驟:

  1. 對像如果沒實現Symbol.iterator那就去實現
  2. 對象的Symbol.iterator函數要返回一個iterator
  3. iterator返回一個對象,對像中至少要包含一個next方法來獲取
  4. next方法返回兩個值valuedone

現在說說怎麼使object變為可迭代的

上面我們已經鋪墊了這麼多了,我們說了javascript中object是不能被迭代了,因為沒有實現iterable ,現在讓我們來實踐一下讓object變的可迭代。

第一步: 先嘗試著使用for...of遍歷object

下面這樣寫肯定是不行的

constobj={name:'helios',age:23}for(letitofobj){console.log(it)}// TypeError: obj is not iterable

第二步: 讓object實現iterable接口

constobj={name:'helios',age:23,[Symbol.iterator]:function(){letage=23;constiterator={next(){return{value:age,done:age++>24}}}returniterator}}

如果iterableiterable是一個對象的話,上面的代碼可以簡化為:

functioniterOver(){letage=23;constiterable={[Symbol.iterator](){returnthis},next(){return{value:age,done:age++>24}}}returniterable}for(letiofiterOver()){console.log(i)}

現在生成器(generator)可以出場了

我們如果每次想把一個不能迭代的對像變為可迭代的對象,在實現Symbol.iterator的時候,每次都要寫返回一個對象,對象裡面有對應的next方法,next方法必須返回valua和done兩個值。

這樣寫的話每次都會很繁,好在ES6提供了generator(生成器)能生成迭代器,我們來看簡化後的代碼:

constobj={name:'helios',age:23,[Symbol.iterator]:function*(){while(this.age<=24)yieldthis.age++}}for(letitofobj){console.log(it)}

讓object可迭代真的有意義麼

知乎的這個回答是很有水平的了:為什麼es6裡的object不可迭代?

在stackoverflow中也有很高質量的回答: Why are Objects not Iterable in JavaScript?

在上面的回答中從技術方面說了為什麼Object不能迭代(沒有實現iterable),還說了以什麼樣的方式去遍歷Object是個難題,所以把如何迭代的方式去留給了開發者。

但是還是要思考的一個問題就是:我們真有必要去迭代對象字面量麼?

想一下我們要迭代對象字面量的什麼呢?是keys還是values亦或者是entries ,這三種方式在ES6提供的新的數據類型map裡面都有呀,完全是可以代替object的。在這裡不說objectmap的區別,只是說說在ES6以後我們想把兩個事物關聯起來的時候,不一定要非得是用对象字面量了, map支持的更好一下。

對於什麼時候用對象字面量(object)什麼時候使用map我們可以做一下總結:

  • 對象字面量(object)應該是靜態的,也就是說我們應該已經知道了裡面有多少個,和對象的屬性有什麼
  • 使用對象字面量(object)的一般場景有:
  • 不需要去遍歷對象字面量(object)的所有屬性的時候
  • 我們知道了裡面有多少個屬性和對象的屬性是什麼的時候
  • 需要去JSON.stringifyJSON.parse時候
  • 其他的情況用map,其他的情況包括:
  • key不是字符串或者symbol的時候
  • 需要去遍歷的時候
  • 要得到長度的時候
  • 遍歷的時候對順序有要求的(對象字面量(object)可能不是按照你寫的順序)

也並不說是map就肯定比對象字面量(object)好, map也有如下的缺點:

  • 不能使用對象解構
  • 不能JSON.stringify / JSON.parse

參考


文章首發


本文已經默認你已經知道generator是什麼以及for...of和數據類型map怎麼用了。

前ES6的時代怎麼遍歷

先來一道思考題:

通過下面的變量1. 尋找xiaohong(假設名稱唯一)是否喜歡basketball 2. 所有同學的名字

conststudents={xiaohong:{age:'22',fav:['sleep','basketball'],teachers:{english:'daming',chinense:'helios',math:['helios2','helios3']}},xiaoming:{age:'22',fav:['sleep','basketball','football'],teachers:{english:'daming',chinense:'helios',math:['helios2','helios3']}},}

對於第一個問題來說,我們可以使用各種循環語句: for/while

for(leti=0;i<students[xiaoming].fav.length;i++){if(students[xiaoming].fav[i]==='basketball')console.log(true)}leti=0;while(i++<students[xiaoming].fav.length){if(students[xiaoming].fav[i]==='basketball')console.log(true)}

for...of

for(letitemofstudents[xiaoming].fav){if(item==='basketball')console.log(true)}

那麼對於第二個問題來說,因為for/while是不能遍歷對象的,所以行不通,但是對像有一個專屬的遍歷方法for...in

我們來看一下怎麼通過for...in來遍歷:

for(letstuinstudents){console.log(stu)}

你可能會想了,通過for...in去遍歷數組會怎樣呢?我們看一下通過for...in去遍歷:

for(letiteminstudents[xiaoming].fav){console.log(item)// 或者去判断
}

哎呀,通過for...in不也照樣能實現數組的遍歷麼,那為什麼不歸結到數組的遍歷裡面去呢!這裡面還有一些細節需要去了解(這也是上面的“對像有一個專屬的遍歷方法”為什麼加粗),我們通過一段代碼去解釋:

const num = [ 5 , 6 , 7 ] for ( let i in num ) { console . log ( i + 1 )} // 01 // 11 // 21

這是因為for-in是為普通對象({key: value})設計的,所以只能遍歷到字符串類型的鍵。

還有下面這個雖然不常用,但是也是不得不說的:

const arr = [ 5 , 6 , 7 ] arr . foo = function () {} for ( let i in arr ) { console . log ( i ) } // 5 // 6 // 7 // foo !!!

foo屬於arr上面的方法,被遍歷出來是說的過去的。

那麼用for...of我們來看看會怎麼樣

for(letstuofstudents){}// Uncaught TypeError: students is not iterable

is not iterable ,這個iterable是神馬東西,我們接下來下面一步步的看。

先從可迭代(iterable)和迭代器(iterator)說起

iterable是ES6對iteration(迭代/遍歷)引入的接口。

如果一個對像被視為iterable(可迭代)那麼它一定有一個Symbol.iterator屬性,這個屬性返回一個iterator(迭代器)方法,這個方法返回一個規定的對象(這個後面會說)。也就是說iterableiterator的工廠, iterable能夠創建iteratoriterator是用於遍歷數據結構中元素的指針。

兩者之間的關係

Axel Rauschmaye大神的圖簡直不能再清晰了。

數據消費者: javascript本身提供的消費語句結構,例如for...of循環和spread operator (...)數據源:數據消費者能夠通過不同的源(Array,string)得到供數據消費者消費的值;

數據消費者支持所有的數據源這是不可以行的,因為還可能增加新的數據消費者數據源。因此ES6引入了Iterable接口數據源去實現,數據消費者去使用

可迭代協議(iterable protocol)和迭代器協議(iterator protocol)

可迭代協議(iterable protocol)

可迭代協議(iterable protocol)是允許js對象能夠自定義自己的迭代行為。

簡單的說只要對像有Symbol.iterator這個屬性就是可迭代的,我們可以通過重寫(一些對象實現了iterable,比如Array,string)/添加(對於沒有實現iterable的對像比如object,可以添加這個屬性,使之變為可迭代的)該熟悉使之變為可迭代的。

當一個對象需要被迭代(for...of或者spread operator )的時候,他的Symbol.iterator函數被調用並且無參數,然後返回一個迭代器。

迭代器協議(iterator protocol)

迭代器協議定義了一種標準的方式來產生一個有限或無限序列的值。

當一個對像被認為是一個迭代器的時候,它會至少實現next()方法, next()方法返回兩個屬性value (d迭代器返回的值)和done (迭代時候已經結束)。

還有幾個可選的方法可以被實現,具體請看: sec-iterator-interface

iterable協議iterator協議還有next之間的關係

blank

來源於網絡

然後談談ES6中的for...of說起

再文章的最開始我們已經說了再前ES6的時候,如何去遍歷。現在我們說說ES6新增的for...of的作用。

for...of能遍歷的集合

只要是實現了Interable接口的數據類型都能被遍歷。

javascript內部實現的有: - Array - String - Map - Set - arguments - DOM data structures

並不是所有的iterable內容都來源於數據結構,也能通過在運行中計算出來,例如所有ES6的主要數據結構有三個方法能夠返回iterable對象。

  • entries() 返回一個可遍歷的entries
  • keys() 返回一個可遍歷的entries 的keys。
  • values() 返回一個可遍歷的entries 的values。

如果for...of不能遍歷怎麼辦

那就數據結構(數據源)去實現iterable就可以了。

用通俗的話說就是,你如果要遍歷一個對象的話,有一下幾個步驟:

  1. 對像如果沒實現Symbol.iterator那就去實現
  2. 對象的Symbol.iterator函數要返回一個iterator
  3. iterator返回一個對象,對像中至少要包含一個next方法來獲取
  4. next方法返回兩個值valuedone

現在說說怎麼使object變為可迭代的

上面我們已經鋪墊了這麼多了,我們說了javascript中object是不能被迭代了,因為沒有實現iterable ,現在讓我們來實踐一下讓object變的可迭代。

第一步: 先嘗試著使用for...of遍歷object

下面這樣寫肯定是不行的

constobj={name:'helios',age:23}for(letitofobj){console.log(it)}// TypeError: obj is not iterable

第二步: 讓object實現iterable接口

constobj={name:'helios',age:23,[Symbol.iterator]:function(){letage=23;constiterator={next(){return{value:age,done:age++>24}}}returniterator}}

如果iterableiterable是一個對象的話,上面的代碼可以簡化為:

functioniterOver(){letage=23;constiterable={[Symbol.iterator](){returnthis},next(){return{value:age,done:age++>24}}}returniterable}for(letiofiterOver()){console.log(i)}

現在生成器(generator)可以出場了

我們如果每次想把一個不能迭代的對像變為可迭代的對象,在實現Symbol.iterator的時候,每次都要寫返回一個對象,對象裡面有對應的next方法,next方法必須返回valua和done兩個值。

這樣寫的話每次都會很繁,好在ES6提供了generator(生成器)能生成迭代器,我們來看簡化後的代碼:

constobj={name:'helios',age:23,[Symbol.iterator]:function*(){while(this.age<=24)yieldthis.age++}}for(letitofobj){console.log(it)}

讓object可迭代真的有意義麼

知乎的這個回答是很有水平的了:為什麼es6裡的object不可迭代?

在stackoverflow中也有很高質量的回答: Why are Objects not Iterable in JavaScript?

在上面的回答中從技術方面說了為什麼Object不能迭代(沒有實現iterable),還說了以什麼樣的方式去遍歷Object是個難題,所以把如何迭代的方式去留給了開發者。

但是還是要思考的一個問題就是:我們真有必要去迭代對象字面量麼?

想一下我們要迭代對象字面量的什麼呢?是keys還是values亦或者是entries ,這三種方式在ES6提供的新的數據類型map裡面都有呀,完全是可以代替object的。在這裡不說objectmap的區別,只是說說在ES6以後我們想把兩個事物關聯起來的時候,不一定要非得是用对象字面量了, map支持的更好一下。

對於什麼時候用對象字面量(object)什麼時候使用map我們可以做一下總結:

  • 對象字面量(object)應該是靜態的,也就是說我們應該已經知道了裡面有多少個,和對象的屬性有什麼
  • 使用對象字面量(object)的一般場景有:
  • 不需要去遍歷對象字面量(object)的所有屬性的時候
  • 我們知道了裡面有多少個屬性和對象的屬性是什麼的時候
  • 需要去JSON.stringifyJSON.parse時候
  • 其他的情況用map,其他的情況包括:
  • key不是字符串或者symbol的時候
  • 需要去遍歷的時候
  • 要得到長度的時候
  • 遍歷的時候對順序有要求的(對象字面量(object)可能不是按照你寫的順序)

也並不說是map就肯定比對象字面量(object)好, map也有如下的缺點:

  • 不能使用對象解構
  • 不能JSON.stringify / JSON.parse

參考


文章首發


本文已經默認你已經知道generator是什麼以及for...of和數據類型map怎麼用了。

前ES6的時代怎麼遍歷

先來一道思考題:

通過下面的變量1. 尋找xiaohong(假設名稱唯一)是否喜歡basketball 2. 所有同學的名字

conststudents={xiaohong:{age:'22',fav:['sleep','basketball'],teachers:{english:'daming',chinense:'helios',math:['helios2','helios3']}},xiaoming:{age:'22',fav:['sleep','basketball','football'],teachers:{english:'daming',chinense:'helios',math:['helios2','helios3']}},}

對於第一個問題來說,我們可以使用各種循環語句: for/while

for(leti=0;i<students[xiaoming].fav.length;i++){if(students[xiaoming].fav[i]==='basketball')console.log(true)}leti=0;while(i++<students[xiaoming].fav.length){if(students[xiaoming].fav[i]==='basketball')console.log(true)}

for...of

for(letitemofstudents[xiaoming].fav){if(item==='basketball')console.log(true)}

那麼對於第二個問題來說,因為for/while是不能遍歷對象的,所以行不通,但是對像有一個專屬的遍歷方法for...in

我們來看一下怎麼通過for...in來遍歷:

for(letstuinstudents){console.log(stu)}

你可能會想了,通過for...in去遍歷數組會怎樣呢?我們看一下通過for...in去遍歷:

for(letiteminstudents[xiaoming].fav){console.log(item)// 或者去判断
}

哎呀,通過for...in不也照樣能實現數組的遍歷麼,那為什麼不歸結到數組的遍歷裡面去呢!這裡面還有一些細節需要去了解(這也是上面的“對像有一個專屬的遍歷方法”為什麼加粗),我們通過一段代碼去解釋:

const num = [ 5 , 6 , 7 ] for ( let i in num ) { console . log ( i + 1 )} // 51 // 61 // 71

這是因為for-in是為普通對象({key: value})設計的,所以只能遍歷到字符串類型的鍵。

還有下面這個雖然不常用,但是也是不得不說的:

const arr = [ 5 , 6 , 7 ] arr . foo = function () {} for ( let i in arr ) { console . log ( i ) } // 5 // 6 // 7 // foo !!!

foo屬於arr上面的方法,被遍歷出來是說的過去的。

那麼用for...of我們來看看會怎麼樣

for(letstuofstudents){}// Uncaught TypeError: students is not iterable

is not iterable ,這個iterable是神馬東西,我們接下來下面一步步的看。

先從可迭代(iterable)和迭代器(iterator)說起

iterable是ES6對iteration(迭代/遍歷)引入的接口。

如果一個對像被視為iterable(可迭代)那麼它一定有一個Symbol.iterator屬性,這個屬性返回一個iterator(迭代器)方法,這個方法返回一個規定的對象(這個後面會說)。也就是說iterableiterator的工廠, iterable能夠創建iteratoriterator是用於遍歷數據結構中元素的指針。

兩者之間的關係

Axel Rauschmaye大神的圖簡直不能再清晰了。

數據消費者: javascript本身提供的消費語句結構,例如for...of循環和spread operator (...)數據源:數據消費者能夠通過不同的源(Array,string)得到供數據消費者消費的值;

數據消費者支持所有的數據源這是不可以行的,因為還可能增加新的數據消費者數據源。因此ES6引入了Iterable接口數據源去實現,數據消費者去使用

可迭代協議(iterable protocol)和迭代器協議(iterator protocol)

可迭代協議(iterable protocol)

可迭代協議(iterable protocol)是允許js對象能夠自定義自己的迭代行為。

簡單的說只要對像有Symbol.iterator這個屬性就是可迭代的,我們可以通過重寫(一些對象實現了iterable,比如Array,string)/添加(對於沒有實現iterable的對像比如object,可以添加這個屬性,使之變為可迭代的)該熟悉使之變為可迭代的。

當一個對象需要被迭代(for...of或者spread operator )的時候,他的Symbol.iterator函數被調用並且無參數,然後返回一個迭代器。

迭代器協議(iterator protocol)

迭代器協議定義了一種標準的方式來產生一個有限或無限序列的值。

當一個對像被認為是一個迭代器的時候,它會至少實現next()方法, next()方法返回兩個屬性value (d迭代器返回的值)和done (迭代時候已經結束)。

還有幾個可選的方法可以被實現,具體請看: sec-iterator-interface

iterable協議iterator協議還有next之間的關係

blank

來源於網絡

然後談談ES6中的for...of說起

再文章的最開始我們已經說了再前ES6的時候,如何去遍歷。現在我們說說ES6新增的for...of的作用。

for...of能遍歷的集合

只要是實現了Interable接口的數據類型都能被遍歷。

javascript內部實現的有: - Array - String - Map - Set - arguments - DOM data structures

並不是所有的iterable內容都來源於數據結構,也能通過在運行中計算出來,例如所有ES6的主要數據結構有三個方法能夠返回iterable對象。

  • entries() 返回一個可遍歷的entries
  • keys() 返回一個可遍歷的entries 的keys。
  • values() 返回一個可遍歷的entries 的values。

如果for...of不能遍歷怎麼辦

那就數據結構(數據源)去實現iterable就可以了。

用通俗的話說就是,你如果要遍歷一個對象的話,有一下幾個步驟:

  1. 對像如果沒實現Symbol.iterator那就去實現
  2. 對象的Symbol.iterator函數要返回一個iterator
  3. iterator返回一個對象,對像中至少要包含一個next方法來獲取
  4. next方法返回兩個值valuedone

現在說說怎麼使object變為可迭代的

上面我們已經鋪墊了這麼多了,我們說了javascript中object是不能被迭代了,因為沒有實現iterable ,現在讓我們來實踐一下讓object變的可迭代。

第一步: 先嘗試著使用for...of遍歷object

下面這樣寫肯定是不行的

constobj={name:'helios',age:23}for(letitofobj){console.log(it)}// TypeError: obj is not iterable

第二步: 讓object實現iterable接口

constobj={name:'helios',age:23,[Symbol.iterator]:function(){letage=23;constiterator={next(){return{value:age,done:age++>24}}}returniterator}}

如果iterableiterable是一個對象的話,上面的代碼可以簡化為:

functioniterOver(){letage=23;constiterable={[Symbol.iterator](){returnthis},next(){return{value:age,done:age++>24}}}returniterable}for(letiofiterOver()){console.log(i)}

現在生成器(generator)可以出場了

我們如果每次想把一個不能迭代的對像變為可迭代的對象,在實現Symbol.iterator的時候,每次都要寫返回一個對象,對象裡面有對應的next方法,next方法必須返回valua和done兩個值。

這樣寫的話每次都會很繁,好在ES6提供了generator(生成器)能生成迭代器,我們來看簡化後的代碼:

constobj={name:'helios',age:23,[Symbol.iterator]:function*(){while(this.age<=24)yieldthis.age++}}for(letitofobj){console.log(it)}

讓object可迭代真的有意義麼

知乎的這個回答是很有水平的了:為什麼es6裡的object不可迭代?

在stackoverflow中也有很高質量的回答: Why are Objects not Iterable in JavaScript?

在上面的回答中從技術方面說了為什麼Object不能迭代(沒有實現iterable),還說了以什麼樣的方式去遍歷Object是個難題,所以把如何迭代的方式去留給了開發者。

但是還是要思考的一個問題就是:我們真有必要去迭代對象字面量麼?

想一下我們要迭代對象字面量的什麼呢?是keys還是values亦或者是entries ,這三種方式在ES6提供的新的數據類型map裡面都有呀,完全是可以代替object的。在這裡不說objectmap的區別,只是說說在ES6以後我們想把兩個事物關聯起來的時候,不一定要非得是用对象字面量了, map支持的更好一下。

對於什麼時候用對象字面量(object)什麼時候使用map我們可以做一下總結:

  • 對象字面量(object)應該是靜態的,也就是說我們應該已經知道了裡面有多少個,和對象的屬性有什麼
  • 使用對象字面量(object)的一般場景有:
  • 不需要去遍歷對象字面量(object)的所有屬性的時候
  • 我們知道了裡面有多少個屬性和對象的屬性是什麼的時候
  • 需要去JSON.stringifyJSON.parse時候
  • 其他的情況用map,其他的情況包括:
  • key不是字符串或者symbol的時候
  • 需要去遍歷的時候
  • 要得到長度的時候
  • 遍歷的時候對順序有要求的(對象字面量(object)可能不是按照你寫的順序)

也並不說是map就肯定比對象字面量(object)好, map也有如下的缺點:

  • 不能通過...去解構
  • 不能JSON.stringify / JSON.parse

參考

What do you think?

Written by marketer

blank

2019 力扣杯—全國高校春季編程大賽等你來戰!

blank

React 16 新特性全解(中)