How do I loop through or enumerate a JavaScript ob

2018-12-30 22:29发布

I have a JavaScript object like the following:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

Now I want to loop through all p elements (p1, p2, p3...) And get their keys and values. How can I do that?

I can modify the JavaScript object if necessary. My ultimate goal is to loop through some key value pairs and if possible I want to avoid using eval.

30条回答
唯独是你
2楼-- · 2018-12-30 22:45

You can use the for-in loop as shown by others. However, you also have to make sure that the key you get is an actual property of an object, and doesn't come from the prototype.

Here is the snippet:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " -> " + p[key]);
    }
}

查看更多
春风洒进眼中
3楼-- · 2018-12-30 22:45

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " = " + p[key]);
    }
}
<p>
  Output:<br>
  p1 = values1<br>
  p2 = values2<br>
  p3 = values3
</p>

查看更多
孤独总比滥情好
4楼-- · 2018-12-30 22:46

If you want to iterate over non-enumerable properties as well, you can use Object.getOwnPropertyNames(obj) to return an array of all properties (enumerable or not) found directly upon a given object.

var obj = Object.create({}, {
  // non-enumerable property
  getFoo: {
    value: function() { return this.foo; },
    enumerable: false
  }
});

obj.foo = 1; // enumerable property

Object.getOwnPropertyNames(obj).forEach(function (name) {
  document.write(name + ': ' + obj[name] + '<br/>');
});

查看更多
浮光初槿花落
5楼-- · 2018-12-30 22:47

It's interesting people in these answers have touched on both Object.keys() and for...of but never combined them:

var map = {well:'hello', there:'!'};
for (let key of Object.keys(map))
    console.log(key + ':' + map[key]);

You can't just for...of an Object because it's not an iterator, and for...index or .forEach()ing the Object.keys() is ugly/inefficient.
I'm glad most people are refraining from for...in (with or without checking .hasOwnProperty()) as that's also a bit messy, so other than my answer above, I'm here to say...


You can make ordinary object associations iterate! Behaving just like Maps with direct use of the fancy for...of
DEMO working in Chrome and FF (I assume ES6 only)

var ordinaryObject = {well:'hello', there:'!'};
for (let pair of ordinaryObject)
    //key:value
    console.log(pair[0] + ':' + pair[1]);

//or
for (let [key, value] of ordinaryObject)
    console.log(key + ':' + value);

So long as you include my shim below:

//makes all objects iterable just like Maps!!! YAY
//iterates over Object.keys() (which already ignores prototype chain for us)
Object.prototype[Symbol.iterator] = function() {
    var keys = Object.keys(this)[Symbol.iterator]();
    var obj = this;
    var output;
    return {next:function() {
        if (!(output = keys.next()).done)
            output.value = [output.value, obj[output.value]];
        return output;
    }};
};

Without having to create a real Map object that doesn't have the nice syntactic sugar.

var trueMap = new Map([['well', 'hello'], ['there', '!']]);
for (let pair of trueMap)
    console.log(pair[0] + ':' + pair[1]);

In fact, with this shim, if you still wanted to take advantage of Map's other functionality (without shimming them all in) but still wanted to use the neat object notation, since objects are now iterable you can now just make a Map from it!

//shown in demo
var realMap = new Map({well:'hello', there:'!'});

For those who don't like to shim, or mess with prototype in general, feel free to make the function on window instead, calling it something like getObjIterator() then;

//no prototype manipulation
function getObjIterator(obj) {
    //create a dummy object instead of adding functionality to all objects
    var iterator = new Object();

    //give it what the shim does but as its own local property
    iterator[Symbol.iterator] = function() {
        var keys = Object.keys(obj)[Symbol.iterator]();
        var output;

        return {next:function() {
            if (!(output = keys.next()).done)
                output.value = [output.value, obj[output.value]];
            return output;
        }};
    };

    return iterator;
}

Now you can just call it as an ordinary function, nothing else is affected

var realMap = new Map(getObjIterator({well:'hello', there:'!'}))

or

for (let pair of getObjIterator(ordinaryObject))

There's no reason why that wouldn't work.

Welcome to the future.

查看更多
爱死公子算了
6楼-- · 2018-12-30 22:47

Considering ES6 I'd like to add my own spoon of sugar and provide one more approach to iterate over object's properties.

Since plain JS object isn't iterable just out of box, we aren't able to use for..of loop for iterating over its content. But no one can stop us to make it iterable.

Let's we have book object.

let book = {
  title: "Amazing book",
  author: "Me",
  pages: 3
}

book[Symbol.iterator] = function(){

  let properties = Object.keys(this); // returns an array with property names
  let counter = 0;
  let isDone = false;

  let next = () => {
    if(counter >= properties.length){
      isDone = true;
    }
    return { done: isDone, value: this[properties[counter++]] }
  }

  return { next };
}

Since we've made it we can use it this way:

for(let pValue of book){
  console.log(pValue);
}
------------------------
Amazing book
Me
3

Or if you know the power of ES6 generators, so you certainly can make the code above much shorter.

book[Symbol.iterator] = function *(){

  let properties = Object.keys(this);
  for (let p of properties){
    yield this[p];
  }

}

Sure, you can apply such behavior for all objects with making Object iterable on prototype level.

Object.prototype[Symbol.iterator] = function() {...}

Also, objects that comply with the iterable protocol can be used with the new ES2015 feature spread operator thus we can read object property values as an array.

let pValues = [...book];
console.log(pValues);
-------------------------
["Amazing book", "Me", 3]

Or you can use destructuring assignment:

let [title, , pages] = book; // notice that we can just skip unnecessary values
console.log(title);
console.log(pages);
------------------
Amazing book
3

You can check out JSFiddle with all code I've provided above.

查看更多
与君花间醉酒
7楼-- · 2018-12-30 22:48

Since es2015 is getting more and more popular I am posting this answer which include usage of generator and iterator to smoothly iterate through [key, value] pairs. As it is possible in other languages for instance Ruby.

Ok here is a code:

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
  [Symbol.iterator]: function* () {
    for (const i of Object.keys(this)) {
      yield [i, this[i]];
    }
  }
};

for (const [k, v] of MyObject) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

All information about how can you do an iterator and generator you can find at developer Mozilla page.

Hope It helped someone.

EDIT:

ES2017 will include Object.entries which will make iterating over [key, value] pairs in objects even more easier. It is now known that it will be a part of a standard according to the ts39 stage information.

I think it is time to update my answer to let it became even more fresher than it's now.

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
};

for (const [k, v] of Object.entries(MyObject)) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

You can find more about usage on MDN page

查看更多
登录 后发表回答