简体   繁体   中英

How do I find objects with a property inside another object in JavaScript

I have a object with all my users, like so: var users = {user1:{}, user2:{}} , And every user has a isPlaying property. How do I get all users that have isPlaying false?

You should use Object.keys , Array.prototype.filter and Array.prototype.map :

// This will turn users object properties into a string array
// of user names
var userNames = Object.keys(users);

// #1 You need to filter which users aren't playing. So, you
// filter accessing users object by user name and you check that
// user.isPlaying is false
//
// #2 Using Array.prototype.map, you turn user names into user objects
// by projecting each user name into the user object!
var usersNotPlaying = userNames.filter(function(userName) { 
   return !users[userName].isPlaying; 
}).map(function(userName) {
   return users[userName];
});

If it would be done using ECMA-Script 6, you could do using arrow functions:

// Compact and nicer!
var usersNotPlaying = Object.keys(users)
                       .filter(userName => users[userName].isPlaying)
                       .map(userName => users[userName]);

Using Array.prototype.reduce

As @RobG has pointed out, you can also use Array.prototype.reduce .

While I don't want to overlap his new and own answer, I believe that reduce approach is more practical if it returns an array of user objects not playing .

Basically, if you return an object instead of an array, the issue is that another caller (ie a function which calls the one doing the so-called reduce ) may need to call reduce again to perform a new operation, while an array is already prepared to fluently call other Array.prototype functions like map , filter , forEach ...

The code would look this way:

// #1 We turn user properties into an array of property names
// #2 Then we call "reduce" on the user property name array. Reduce
//    takes a callback that will be called for every array item and it receives
//    the array reference given as second parameter of "reduce" after 
//    the callback.
// #3 If the user is not playing, we add the user object to the resulting array
// #4 Finally, "reduce" returns the array that was passed as second argument
//    and contains user objects not playing ;)
var usersNotPlaying = Object.keys(users).reduce(function (result, userName) {
    if (!users[userName].isPlaying) 
        result.push(users[userName]);
    return result;
}, []); // <-- [] is the new array which will accumulate each user not playing

Clearly using Array.prototype.reduce concentrates both map and filter in a single loop and, in large array, reducing should outperform "filter+map" approach, because looping a large array twice once to filter users not playing and looping again to map them into objects again can be heavy...

Summary: I would still use filter+map over reduce when we talk about few items because sometimes readability/productivity is more important than optimization, and in our case, it seems like filter+map approach requires less explanations (self-documented code!) than reduce.

Anyway, readability/productivity is subjective to who does the actual coding...

Iterate through your users object:

var list = [];
for (var key in users) {
    if (users[key].isPlaying === false) {
        list.push(key);
    }
}

This will give you a list of all users who have an isPlaying property that is false .

If you would like all of the user objects where isPlaying is false, you can add the objects themselves instead:

var list = [];
for (var key in users) {
    if (users[key].isPlaying === false) {
        list.push(users[key]);
    }
}

This can also be achieved using Array.prototype.reduce , which is a great all round tool. It starts with getting an array of the names:

var userNames = Object.keys(users);

To return an array just the user names where isPlaying is false, you can do:

var usersNotPlaying = userNames.reduce(function(names, name) {
                        if (!users[name].isPlaying) {
                          names.push(name);
                        }
                        return names}, []);

To return an object of user objects with their names as keys is similar:

var usersNotPlaying = userNames.reduce(function(names, name) {
                        if (!users[name].isPlaying) {
                          names[name] = users[name];
                        }
                        return names}, {});

You could also use forEach in a similar way, however since it returns undefined the object or array collecting the members must be initialised in an outer scope first:

var usersNotPlaying = {};
userNames.forEach(function(name) {
  if (!users[name].isPlaying) {
    usersNotPlaying[name] = users[name];
  }
});

You can also use for..in :

var usersNotPlaying = {};
for (var user in users) {
  if (users.hasOwnProperty(user) && !users[user].isPlaying) {
    usersNotPlaying[user] = users[user];
  }
}

All of the above can return an array of names, array of user objects or object of user objects. Choose whatever suits. ;-)

Please try the JS code below: set all the isPlaying to false.

var json_object={};//{"user1":{"isPlaying":"false"},"user2":{"isPlaying":"ture"}};
json_object['user1']={"isPlaying":"false"};
json_object['user2']={"isPlaying":"ture"};
console.log(json_object); 
for(var key in json_object){
    if(json_object[key].isPlaying === "false"){/*do what you want*/}
}
console.log(json_object);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM