為什麼es6里的object不可迭代?
即不能用for of 遍歷
@魯小夫 的答案是從技術實現的角度說的,即直接原因是在Object.prototype上沒有實現 [Symbol.iterator]() 方法。不過題主也許想問的是為什麼這樣設計,畢竟前ES6時代的 for-in 可以遍歷所有屬性。下面我講一下我的看法。
Iterator的作用是將迭代行為與collection本身分離。但每次都要 new XXXIterator(collection) 很麻煩,[Symbol.iterator]() 的機制相當於提供了默認迭代器。那麼問題就是,如果允許直接 for-of 一個普通對象,其默認迭代行為應該是什麼?這個問題乍一看,似乎沒什麼,直接照搬 for-in 的行為嘛。但是其實一直以來 for-in 的行為就受到詬病,在許多場合我們只希望拿 own properties,因此不得不在 for-in 里用 hasOwnProperty/propertyIsEnumerable 之類的方法過濾。而這是一個低效又麻煩的方式。所以在ES5之後,我們一般不再使用 for-in,而是使用 Object.keys(obj).forEach(...) 來遍歷所有 own properties。那好,我們用這個行為吧?但是慢著,ES6引入了Symbol,我們 for-of 的時候要不要算上 symbols 呢?假如覺得應該包括的話,那麼又有一個問題,是不是要按照 Object.keys() 一樣排除掉 enumerable 為 false 的呢?
總結起來,對象的property至少有三個方面的因素:
1. property的來源:是僅 own property 還是包括原型鏈上的;2. key的類型:是僅 string 還是包括 symbol 在內;3. property的[[Enumerable]] attribute:是僅可枚舉(enumerable為true)還是包括不可枚舉的。這三個因素組合出來就有8種可能。
如果再考慮迭代 key、value、[key, value] 這三種可能,就多達24種組合。
到底哪一種適合作為默認迭代行為?雖然我們可以排除一些,但是要收斂到唯一一種非常難。不像數組,我們直覺上默認迭代就應該那樣;對於對象,有太多不同的用法。既然如此,我們不如把如何迭代留給程序員。比如你可以:for (const k of Object.keys(obj)) ... // enumerable own keys
for (const [k, v] of Object.entries(obj)) ... // enumerable own [key, value]s
for (const k of Object.getOwnPropertyNames(obj)) // all own keys
for (const s of Object.getOwnPropertySymbols(obj)) // all own symbols
for (const k of Reflect.ownKeys(obj)) // all own keys (include symbols)
其他組合可以自行實現(比如寫個generator)。
最後,理論上未來社區如果形成一致意見,委員會也可以添加 Object.prototype[Symbol.iterator]() 方法,指定某種行為,比如與 Reflect.ownKeys() 對應的 own entries,那樣就可以直接 for-of 對象了。不過我認為這種可能性基本為零。
瀉藥
因為 object 沒有實現 iterator protocol答主應該是問什麼不部署Iterator介面。這個阮一峰老師的es6入門有說明過。大概就是:
- 對象的哪個屬性先遍歷,哪個屬性後遍歷是不確定的,需要開發者手動指定。
- 部署了遍歷器介面的對象其實就是ES6里的Map結構,如果你需要的話,直接使用Map就好了
這裡貼上原文:
對象(Object)之所以沒有默認部署Iterator介面,是因為對象的哪個屬性先遍歷,哪個屬性後遍歷是不確定的,需要開發者手動指定。本質上,遍歷器是一種線性處理,對於任何非線性的數據結構,部署遍歷器介面,就等於部署一種線性轉換。不過,嚴格地說,對象部署遍歷器介面並不是很必要,因為這時對象實際上被當作Map結構使用,ES5沒有Map結構,而ES6原生提供了。
換 es6 map
因為已經有Map了
推薦閱讀:
※作為一名前端開發工程師,哪門後端語言最適合掌握?
※2016 年前端開發領域有什麼趨勢值得關注?
※如何系統的學習nodejs?
※為什麼互聯網公司開始用node.js做web服務的中間件?有什麼好處嗎?
※前端構建工具webpack有什麼缺陷?
TAG:JavaScript | ECMAScript2015 |