可以迭代大部分?jǐn)?shù)據(jù)類型的 for…of 為什么不能遍歷普通對(duì)象?
加入我們一起學(xué)習(xí),天天進(jìn)步
for…of 及其使用
for...of的語(yǔ)法:
for (variable of iterable) {// statement}// variable:每個(gè)迭代的屬性值被分配給該變量。// iterable:一個(gè)具有可枚舉屬性并且可以迭代的對(duì)象。
常用用法
{// 迭代字符串const iterable = 'ES6';for (const value of iterable) {console.log(value);}// Output:// "E"// "S"// "6"}{// 迭代數(shù)組const iterable = ['a', 'b'];for (const value of iterable) {console.log(value);}// Output:// a// b}{// 迭代Set(集合)const iterable = new Set([1, 2, 2, 1]);for (const value of iterable) {console.log(value);}// Output:// 1// 2}{// 迭代Mapconst iterable = new Map([["a", 1], ["b", 2], ["c", 3]]);for (const entry of iterable) {console.log(entry);}// Output:// ["a", 1]// ["b", 2]// ["c", 3]for (const [key, value] of iterable) {console.log(value);}// Output:// 1// 2// 3}{// 迭代Arguments Object(參數(shù)對(duì)象)function args() {for (const arg of arguments) {console.log(arg);}}args('a', 'b');// Output:// a// b}{// 迭代生成器function* foo(){yield 1;yield 2;yield 3;};for (let o of foo()) {console.log(o);}// Output:// 1// 2// 3}
Uncaught TypeError: obj is not iterable
// 普通對(duì)象const obj = {foo: 'value1',bar: 'value2'}for(const item of obj){console.log(item)}// Uncaught TypeError: obj is not iterable
如何用for...of迭代普通對(duì)象
const obj = {foo: 'value1',bar: 'value2'}// 打印由value組成的數(shù)組console.log(Object.values(obj)) // ["value1", "value2"]// 打印由key組成的數(shù)組console.log(Object.keys(obj)) // ["foo", "bar"]// 打印由[key, value]組成的二維數(shù)組// copy(Object.entries(obj))可以把輸出結(jié)果直接拷貝到剪貼板,然后黏貼console.log(Object.entries(obj)) // [["foo","value1"],["bar","value2"]]
const obj = {foo: 'value1',bar: 'value2'}// 方法一:使用for of迭代Object.entries(obj)形成的二維數(shù)組,利用解構(gòu)賦值得到valuefor(const [, value] of Object.entries(obj)){console.log(value) // value1, value2}// 方法二:Map// 普通對(duì)象轉(zhuǎn)Map// Map 可以接受一個(gè)數(shù)組作為參數(shù)。該數(shù)組的成員是一個(gè)個(gè)表示鍵值對(duì)的數(shù)組console.log(new Map(Object.entries(obj)))// 遍歷普通對(duì)象生成的Mapfor(const [, value] of new Map(Object.entries(obj))){console.log(value) // value1, value2}// 方法三:繼續(xù)使用for infor(const key in obj){console.log(obj[key]) // value1, value2}{// 方法四:將【類數(shù)組(array-like)對(duì)象】轉(zhuǎn)換為數(shù)組// 該對(duì)象需具有一個(gè) length 屬性,且其元素必須可以被索引。const obj = {length: 3, // length是必須的,否則什么也不會(huì)打印0: 'foo',1: 'bar',2: 'baz',a: 12 // 非數(shù)字屬性是不會(huì)打印的};const array = Array.from(obj); // ["foo", "bar", "baz"]for (const value of array) {console.log(value);}// Output: foo bar baz}{// 方法五:給【類數(shù)組】部署數(shù)組的[Symbol.iterator]方法【對(duì)普通字符串屬性對(duì)象無(wú)效】const iterable = {0: 'a',1: 'b',2: 'c',length: 3,[Symbol.iterator]: Array.prototype[Symbol.iterator]};for (let item of iterable) {console.log(item); // 'a', 'b', 'c'}}
注意事項(xiàng)
const obj = {foo: 'value1',bar: 'value2',baz: 'value3'}for(const [, value] of Object.entries(obj)){if (value === 'value2') break // 不會(huì)再執(zhí)行下次迭代console.log(value) // value1};[1,2].forEach(item => {if(item == 1) break // Uncaught SyntaxError: Illegal break statementconsole.log(item)});[1,2].forEach(item => {if(item == 1) continue // Uncaught SyntaxError: Illegal continue statement: no surrounding iteration statementconsole.log(item)});[1,2].forEach(item => {if(item == 1) return // 仍然會(huì)繼續(xù)執(zhí)行下一次循環(huán),打印2console.log(item) // 2})
Array.prototype.newArr = () => {};Array.prototype.anotherNewArr = () => {};const array = ['foo', 'bar', 'baz'];for (const value in array) {console.log(value); // 0 1 2 newArr anotherNewArr}for (const value of array) {console.log(value); // 'foo', 'bar', 'baz'}
普通對(duì)象為何不能被 for of 迭代



Iterator(遍歷器)
關(guān)于Iterator(遍歷器),可以參照阮一峰老師寫的《ECMAScript 6 入門教程—異步遍歷器》教程。
如何實(shí)現(xiàn)Symbol.iterator方法,使普通對(duì)象可被 for of 迭代
const arr = [1,2,3];const iterator = arr[Symbol.iterator]();console.log(iterator.next()); // {value: 1, done: false}console.log(iterator.next()); // {value: 2, done: false}console.log(iterator.next()); // {value: 3, done: false}console.log(iterator.next()); // {value: undefined, done: true}
// 普通對(duì)象const obj = {foo: 'value1',bar: 'value2',[Symbol.iterator]() {// 這里Object.keys不會(huì)獲取到Symbol.iterator屬性,原因見(jiàn)下文const keys = Object.keys(obj);let index = 0;return {next: () => {if (index < keys.length) {// 迭代結(jié)果 未結(jié)束return {value: this[keys[index++]],done: false};} else {// 迭代結(jié)果 結(jié)束return { value: undefined, done: true };}}};}}for (const value of obj) {console.log(value); // value1 value2};
console.log([...obj]); // ["value1", "value2"]console.log([...{}]); // console.log is not iterable (cannot read property Symbol(Symbol.iterator))
迭代器模式
const obj = {// 數(shù)據(jù)結(jié)構(gòu)調(diào)整data: ['value1', 'value2'],[Symbol.iterator]() {let index = 0;return {next: () => {if (index < this.data.length) {// 迭代結(jié)果 未結(jié)束return {value: this.data[index++],done: false};} else {// 迭代結(jié)果 結(jié)束return { value: undefined, done: true };}}};}}// 外部調(diào)用for (const value of obj) {console.log(value); // value1 value2}
const obj1 = {data: ['value1', 'value2']}const obj2 = {data: [1, 2]}// 遍歷方法consoleEachData = (obj) => {obj[Symbol.iterator] = () => {let index = 0;return {next: () => {if (index < obj.data.length) {return {value: obj.data[index++],done: false};} else {return { value: undefined, done: true };}}};}for (const value of obj) {console.log(value);}}consoleEachData(obj1); // value1 value2consoleEachData(obj2); // 1 2
一點(diǎn)補(bǔ)充
let aClone = { ...a };// 等同于let aClone = Object.assign({}, a);
??愛(ài)心三連擊 1.看到這里了就點(diǎn)個(gè)在看支持下吧,你的「點(diǎn)贊,在看」是我創(chuàng)作的動(dòng)力。
2.關(guān)注公眾號(hào)
程序員成長(zhǎng)指北,回復(fù)「1」加入Node進(jìn)階交流群!「在這里有好多 Node 開(kāi)發(fā)者,會(huì)討論 Node 知識(shí),互相學(xué)習(xí)」!3.也可添加微信【ikoala520】,一起成長(zhǎng)。
“在看轉(zhuǎn)發(fā)”是最大的支持
評(píng)論
圖片
表情
