在 For Of 循环中使用对象

Posted

技术标签:

【中文标题】在 For Of 循环中使用对象【英文标题】:Using Objects in For Of Loops 【发布时间】:2015-07-05 06:50:30 【问题描述】:

为什么不能在 for of 循环中使用对象?或者这是一个浏览器错误?这段代码在 Chrome 42 中不起作用,说 undefined is not a function:

test =  first: "one"

for(var item of test) 
  console.log(item)

【问题讨论】:

测试是数组还是对象? @KickButtowski,你没看到吗?它绝对是一个对象。 for (let key of Object.keys(test)) ... 【参考方案1】:

for..of loop 仅支持数组等可迭代对象,不支持对象。

要遍历对象的值,请使用:

for (var key in test) 
    var item = test[key];

【讨论】:

@DanielHerr 有一个.iterable 成员函数,当您尝试在一个对象(没有它)上使用它时,就会出现错误。 developer.mozilla.org/en-US/docs/Web/javascript/Reference/… 我的意思是,为什么对象没有那个?原生添加会有什么问题? @DanielHerr 我没有答案,你得问问设计语言的人。 @DanielHerr 如果对象“基类”是可迭代的,那么任何函数/日期/等“子类”以及其他复杂性也将是可迭代的。不过,请参阅 esdiscuss.org/topic/es6-iteration-over-object-values#content-5 以更彻底/准确地讨论您的问题。 有了这个 for..in 解决方案,从技术上讲,您是否还需要检查if (test.hasOwnProperty(key)) ... ?还是不需要?【参考方案2】:

您可以使用以下语法:

const myObject = 
  first: "one",
  second: "two",
;

for (const [key, value] of Object.entries(myObject)) 
  console.log(key, value);  // first one, second two

但是,Object.entries 目前的支持很差 在 IE ios Safari 中不起作用。您可能可能需要一个 polyfill。最新消息见https://caniuse.com/mdn-javascript_builtins_object_entries。

另请参见 Object.keys 仅迭代键,或 Object.values 仅迭代值。

【讨论】:

【参考方案3】:

如果您将数据存储在键值存储中,please use Map 专门为此目的而设计。

如果你必须使用一个对象,ES2017 (ES8) 允许你使用Object.values:

const foo =  a: 'foo', z: 'bar', m: 'baz' ;
for (let value of Object.values(foo)) 
    console.log(value);

如果还不支持,请使用 polyfill:Alternative version for Object.values()

最后,如果您支持不支持此语法的旧环境,您将不得不使用forEachObject.keys

var obj =  a: 'foo', z: 'bar', m: 'baz' ;
Object.keys(obj).forEach(function (prop) 
    var value = obj[prop];
    console.log(value);
);

【讨论】:

不能扩展对象原型来支持这个吗? @SonicSoul:技术上是的,但通常不建议扩展 Object 原型,因为(几乎)所有东西都继承自它。 Object.entries 可以在不接触原型的情况下进行填充。 为什么使用地图而不是对象? 使用这些复杂的例子比简单的for-in 有什么好处吗?【参考方案4】:

ECMAScript 2015/ES6 中的迭代器、可迭代和 for..of 循环

let tempArray = [1,2,3,4,5];

for(element of tempArray) 
  console.log(element);


// 1
// 2
// 3
// 4
// 5

但如果我们这样做

let tempObj = a:1, b:2, c:3;

for(element of tempObj) 
   console.log(element);

// error

我们得到错误是因为 for..of 循环仅适用于 Iterables,即具有 @@iterator 的对象遵守 Iterator 协议,这意味着它必须有一个带有 next 方法的对象。下一个方法不带参数,它应该返回一个具有这两个属性的对象。

done:当为真时表示序列已经结束,假表示可能有更多的值 :这是序列中的当前项

因此,要使对象 Iterablefor..of 一起工作,我们可以:

1 . 通过 Symbol.iterator 属性为对象分配神秘的 @@iterator 属性,使对象成为 Iterable。以下是如何:

let tempObj = a:1, b:2, c:3;

tempObj[Symbol.iterator]= () => (
next: function next () 
return 
    done: Object.keys(this).length === 0,
    value: Object.keys(this).shift()
     
    
  )

for(key in tempObj)
 console.log(key)

// a
// b
// c

2.使用Object.entries,返回一个Iterable

let tempObj = a:1, b:2, c:3;

for(let [key, value] of Object.entries(tempObj)) 
    console.log(key, value);

// a 1
// b 2
// c 3

3.使用Object.keys,方法如下:

let tempObj = a:1, b:2, c:3;
for (let key of Object.keys(tempObj)) 
    console.log(key);


// a
// b
// c

希望对你有帮助!!!!!!

【讨论】:

【参考方案5】:

我用这段代码使对象可迭代:

Object.prototype[Symbol.iterator] = function*() 
 for(let key of Object.keys(this)) 
  yield([ key, this[key] ])
 

用法:

for(let [ key, value ] of )  

或者:

for(let [ key, value ] of Object.entries())  

【讨论】:

不知道为什么这是公认的解决方案。除非它是 polyfill,否则修改原型总是一个糟糕的主意。 @user1703761 这是公认的解决方案,因为它有效。请解释如果它如此可怕会导致什么问题。 有各种各样的问题,主要是前向兼容性问题。一个例子是 Array.prototype.includes 之前的名字 contains 但 Moo Tools 扩展了原型并且实现不兼容,请参阅 bugzilla.mozilla.org/show_bug.cgi?id=1075059 也查找原型库 desaster ;) 我相信这不会有前向兼容性问题,因为如果将迭代器添加到对象,这将覆盖它,如果将迭代器添加到对象子类型,它将使用子类型迭代器。 大家好,修改原型是个坏主意!!!让我们为实际给出问题的答案而感到羞耻!【参考方案6】:

因为对象字面量没有Symbol.iterator 属性。具体来说,你只能用for...of循环遍历String、Array、Map、Set、arguments、NodeList(不广泛支持)和Generator。

要处理 Object Literal 迭代,您有两种选择。

为...在

for(let key in obj)
    console.log(obj[key]); 

Object.keys + forEach

Object.keys(obj).forEach(function(key)
    console.log(obj[key]);
);

【讨论】:

【参考方案7】:

答案是否定的。不可能将 For..Of 与 Object 字面量一起使用。

我同意 Overv 的观点,即 For..Of 仅适用于可迭代对象。 我有完全相同的问题,因为我使用对象通过 for..in 迭代键和值。但我刚刚意识到这就是 ES6 MAPS 和 SETS 的用途。

let test = new Map();
test.set('first', "one");
test.set('second', "two");

for(var item of test) 
  console.log(item); // "one" "two"

因此它实现了不必使用 for..In(通过 hasOwnProperty 验证)和不必使用 Object.keys() 的目标。

此外,您的键不限于字符串。您可以使用数字、对象或其他文字。

【讨论】:

【参考方案8】:

对象字面量没有内置的迭代器,这是使用for...of 循环所必需的。但是,如果您不想麻烦地将自己的[Symbol.iterator] 添加到您的对象中,您可以简单地使用Object.keys() 方法。此方法返回一个 Array 对象,该对象已经具有内置迭代器,因此您可以将其与 for...of 循环一起使用,如下所示:

const myObject = 
    country: "Canada",
    province: "Quebec",
    city: "Montreal"


for (let i of Object.keys(myObject)) 
    console.log("Key:", i, "| Value:", myObject[i]);


//Key: country | Value: Canada
//Key: province | Value: Quebec
//Key: city | Value: Montreal

【讨论】:

每次都使用key比添加一次迭代器更麻烦。此外,Object.keys() 是 ES5。【参考方案9】:

可以在任何给定对象上定义迭代器,这样您就可以为每个对象放置不同的逻辑

var x =  a: 1, b: 2, c: 3 
x[Symbol.iterator] = function* ()
    yield 1;
    yield 'foo';
    yield 'last'

那就直接迭代x

for (let i in x)
    console.log(i);

//1
//foo
//last

可以在Object.prototype 对象上做同样的事情,并为所有对象提供一个通用迭代器

Object.prototype[Symbol.iterator] = function*() 
    for(let key of Object.keys(this)) 
         yield key 
     
 

然后像这样迭代你的对象

var t = a :'foo', b : 'bar'
for(let i of t)
    console.log(t[i]);

或者这样

var it = t[Symbol.iterator](), p;
while(p = it.next().value)
    console.log(t[p])

【讨论】:

【参考方案10】:

我只是做了以下事情来轻松解决我的问题。

for (let key in obj) 
  if(obj.hasOwnProperty(key)
    console.log(`$key: $obj[key]`);
  

【讨论】:

【参考方案11】:

使用Object.keys 来获取键数组怎么样?然后forEach on the Array?

obj =  a: 1, b:2
Object.keys(obj).forEach( key => console.log(`$key => $obj[key]`))

【讨论】:

【参考方案12】:

如何使用

function* entries(obj) 
    for (let key of Object.keys(obj)) 
        yield [key, obj[key]];
    


for ([key, value] of entries(a: "1", b: "2")) 
    console.log(key + " " + value);

【讨论】:

【参考方案13】:

在 ES6 中你可以使用生成器:

var obj = 1: 'a', 2: 'b';

function* entries(obj) 
  for (let key of Object.keys(obj)) 
    yield [key, obj[key]];
  


let generator = entries(obj);

let step1 = generator.next();
let step2 = generator.next();
let step3 = generator.next();

console.log(JSON.stringify(step1)); // "value":["1","a"],"done":false
console.log(JSON.stringify(step2)); // "value":["2","b"],"done":false
console.log(JSON.stringify(step3)); // "done":true

Here is the jsfiddle. 在输出中,您将获得一个带有 "value""done" 键的对象。 "Value" 包含您想要它拥有的所有内容,"done" 是布尔迭代的当前状态。

【讨论】:

【参考方案14】:

使用 Array Destruction 您可以使用 forEach 进行如下迭代

const obj =  a: 5, b: 7, c: 9 ;

Object.entries(obj).forEach(([key, value]) => 
  console.log(`$key $value`); // "a 5", "b 7", "c 9"
);

【讨论】:

以上是关于在 For Of 循环中使用对象的主要内容,如果未能解决你的问题,请参考以下文章

for...in和for...of循环的区别

for循环和for in的区别

for循环for-inforEachfor-of四大循环

for...in 和 for...of 有什么区别

理解ECMAScript 6中的for...of循环

for..in 和 for...of 的区别