Why isn't is possible to use objects in for of loops? Or is this a browser bug? This code doesn't work in Chrome 42, saying undefined is not a function:
test = { first: "one"}
for(var item of test) {
console.log(item)
}
Why isn't is possible to use objects in for of loops? Or is this a browser bug? This code doesn't work in Chrome 42, saying undefined is not a function:
test = { first: "one"}
for(var item of test) {
console.log(item)
}
I made objects iterable with this code:
Object.prototype[Symbol.iterator] = function*() {
for(let key of Object.keys(this)) {
yield([ key, this[key] ])
} }
Usage:
for(let [ key, value ] of {}) { }
Alternativly:
for(let [ key, value ] of Object.entries({})) { }
Object.keys
. One of the nice things about generators is that they can be chained together lazily. The call to Object.keys
ruins the laziness by eagerly creating a new array of the keys. A better solution would be to use for in
with a hasOwnProperty
check or propertyIsEnumerable
check then yielding –
Bascom for in
also eagerly grabs the keys then there's no difference. it's a small thing though, the performance difference is probably negligible. –
Bascom for in
is faster. Can you confirm on your browser? –
Bascom Object.prototype[Symbol.iterator]
can break any other spec-compiant piece of code. If you need to customize built-in class behaviour, subclass it, it's always as simple as that. E.g. same thing but done right. –
Oria The for..of loop only supports iterable objects like arrays, not objects.
To iterate over the values of an object, use:
for (var key in test) {
var item = test[key];
}
Object.values
. –
Isometrics .iterable
member function, which is where the error comes from when you try to use it on an object (which doesn't have it). developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… –
Debility if (test.hasOwnProperty(key)){ ... }
? Or is that not needed? –
Hilaryhilbert {}
, or getting it from json using JSON.Parse
, hasOwnProperty
is globally useless. But…: https://mcmap.net/q/218637/-should-hasownproperty-still-be-used-with-for-in-statements –
Reamonn You can use this syntax:
const myObject = {
first: "one",
second: "two",
};
for (const [key, value] of Object.entries(myObject)) {
console.log(key, value); // first one, second two
}
However, Object.entries
has poor support right now does not work in IE or iOS Safari. You'll probably might need a polyfill. See https://caniuse.com/mdn-javascript_builtins_object_entries for the latest scoop.
See also Object.keys
to iterate just the keys, or Object.values
for just the values.
If you are storing data in a key-value store, please use Map
which is explicitly designed for this purpose.
If you have to use an object though, ES2017 (ES8) allows you to use Object.values
:
const foo = { a: 'foo', z: 'bar', m: 'baz' };
for (let value of Object.values(foo)) {
console.log(value);
}
If that isn't supported yet, use a polyfill: Alternative version for Object.values()
And finally if you're supporting an older environment that don't support this syntax, you'll have to resort to using forEach
and Object.keys
:
var obj = { a: 'foo', z: 'bar', m: 'baz' };
Object.keys(obj).forEach(function (prop) {
var value = obj[prop];
console.log(value);
});
Object.entries
can by polyfilled without touching the prototype. –
Waikiki for-in
? –
Triumph I made objects iterable with this code:
Object.prototype[Symbol.iterator] = function*() {
for(let key of Object.keys(this)) {
yield([ key, this[key] ])
} }
Usage:
for(let [ key, value ] of {}) { }
Alternativly:
for(let [ key, value ] of Object.entries({})) { }
Object.keys
. One of the nice things about generators is that they can be chained together lazily. The call to Object.keys
ruins the laziness by eagerly creating a new array of the keys. A better solution would be to use for in
with a hasOwnProperty
check or propertyIsEnumerable
check then yielding –
Bascom for in
also eagerly grabs the keys then there's no difference. it's a small thing though, the performance difference is probably negligible. –
Bascom for in
is faster. Can you confirm on your browser? –
Bascom Object.prototype[Symbol.iterator]
can break any other spec-compiant piece of code. If you need to customize built-in class behaviour, subclass it, it's always as simple as that. E.g. same thing but done right. –
Oria Iterator, Iterable and for..of loop in ECMAScript 2015/ ES6
let tempArray = [1,2,3,4,5];
for(element of tempArray) {
console.log(element);
}
// 1
// 2
// 3
// 4
// 5
But if we do
let tempObj = {a:1, b:2, c:3};
for(element of tempObj) {
console.log(element);
}
// error
We get error because for..of loop works only on Iterables, that is, the object which has an @@iterator that adheres to Iterator protocol, meaning it must have an object with a next method. The next method takes no arguments and it should return an object with these two properties.
done: signals that the sequence has ended when true, and false means there may be more values value: this is the current item in the sequence
So, to make an object Iterable that is to make it work with for..of we can:
1 .Make an object an Iterable by assigning to it’s mystical @@iterator property through the Symbol.iterator property.Here is how:
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.Use Object.entries, which returns an 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.Use Object.keys, here is how:
let tempObj = {a:1, b:2, c:3};
for (let key of Object.keys(tempObj)) {
console.log(key);
}
// a
// b
// c
Hope this helps!!!!!!
Because object literal does not have the Symbol.iterator property. To be specific, you can only iterate over String, Array, Map, Set, arguments, NodeList(not widely support) and Generator with for...of loop.
To deal with Object Literal iteration, you have two options.
for(let key in obj){
console.log(obj[key]);
}
Object.keys(obj).forEach(function(key){
console.log(obj[key]);
});
The answer is No. It's not possible to use For..Of with Object literals.
I agree with Overv that For..Of is only for iterables. I had exactly the same question because I use Objects to iterate over keys and values with for..in. But I just realized that that's what ES6 MAPS and SETS are for.
let test = new Map();
test.set('first', "one");
test.set('second', "two");
for(var item of test) {
console.log(item); // "one" "two"
}
Hence it achieves the goal of not having to use for..In (validating with hasOwnProperty) and not having to use Object.keys().
Additionally, your keys aren't limited to strings. You can use numbers, objects, or other literals.
Object literals don't have built-in iterators, which are required to work with for...of
loops. However, if you don't want to go thru the trouble of adding your own [Symbol.iterator]
to your object, you can simply use the Object.keys()
method. This method returns an Array
object, which already has a built-in iterator, so you can use it with a for...of
loop like this:
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
It is possible to define an iterator over any giving object, this way you can put different logic for each object
var x = { a: 1, b: 2, c: 3 }
x[Symbol.iterator] = function* (){
yield 1;
yield 'foo';
yield 'last'
}
Then just directly iterate x
for (let i in x){
console.log(i);
}
//1
//foo
//last
It is possible to do the same thing on the Object.prototype
object And have a general iterator for all objects
Object.prototype[Symbol.iterator] = function*() {
for(let key of Object.keys(this)) {
yield key
}
}
then iterate your object like this
var t = {a :'foo', b : 'bar'}
for(let i of t){
console.log(t[i]);
}
Or this way
var it = t[Symbol.iterator](), p;
while(p = it.next().value){
console.log(t[p])
}
I just did the following to easily console out my stuff.
for (let key in obj) {
if(obj.hasOwnProperty(key){
console.log(`${key}: ${obj[key]}`);
}
}
How about using Object.keys to get an array of keys? And then forEach on the Array?
obj = { a: 1, b:2}
Object.keys(obj).forEach( key => console.log(`${key} => ${obj[key]}`))
Using Array Destruction you can iterate it as follows using 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"
});
One-Line answer based on Mozilla doc Generator - Symbol iterator - Add this to your object to make it iterable:
*[Symbol.iterator]() { yield* Object.values(this) }
example 1 - getting values:
const person = {
name: "SeyyedKhandon",
age: 31,
*[Symbol.iterator]() { yield* Object.values(this) }
}
// Now you can use "for of"
for (let value of person) {
console.log(value);
}
// and also you "spread it"
console.log([...person])
example 2 - getting key-values using *[Symbol.iterator]() { yield* Object.entries(this) }
:
const person = {
name: "SeyyedKhandon",
age: 31,
*[Symbol.iterator]() { yield* Object.entries(this) }
}
// for of
for (let item of person) {
console.log("key:",item[0]," -> ", "value:",item[1]);
}
// spread it
console.log([...person])
Also you can add it later:
person[Symbol.iterator]= function*() { yield* Object.entries(person) }
const person = {
name: "SeyyedKhandon",
age: 31,
}
person[Symbol.iterator]= function*() { yield* Object.entries(person) }
// for of
for (let item of person) {
console.log("key:",item[0]," -> ", "value:",item[1]);
}
// spread it
console.log([...person])
What about using
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);
}
in ES6 you could go with generator:
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.
In the output you will get an object with the "value"
and "done"
keys. "Value"
contains everything you want it to have and "done"
is current state of the iteration in bool.
This is from 2015, we are in 2022 and I think we can say that a good way to solve this is adding an iterator.
For example if we had a snippet like this:
const obj = { a: 1, b: 2, c: 3 }
const [first] = obj
It will give us an error that object is not iterable
However, it can be iterated using for ... in
const obj = { a: 1, b: 2, c: 3 }
for (const key in obj) {
console.log('key: ', key)
}
obj
instance iterable?Well it is easy just add the iterable protocol like this:
const obj = { a: 'one', b: 'two', c: 'three' }
obj[Symbol.iterator] = () => {
const entries = Object.entries(obj)
return {
next() {
return {
done: entries.length === 0,
value: entries.shift(),
}
},
}
}
const [first] = obj
const [k, v] = first
console.log(`first: [k: ${k}, v:${v}]`)
// Now we can use for of
for (const [k, v] of obj) {
console.log(`[k:${k}, v:${v}]`)
}
Object.entries(obj)
with Object.keys(obj)
or Object.values(obj)
according to the needs of the project.
© 2022 - 2024 — McMap. All rights reserved.