在 JavaScript 对象数组中按 id 查找对象

I've got an array:

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}, etc.]

I'm unable to change the structure of the array. I'm being passed an id of 45, and I want to get 'bar' for that object in the array.

How do I do this in JavaScript or using jQuery?

转载于:https://stackoverflow.com/questions/7364150/find-object-by-id-in-an-array-of-javascript-objects

29个回答

Use the find() method:

myArray.find(x => x.id === '45').foo;

From MDN:

The find() method returns a value in the array, if an element in the array satisfies the provided testing function. Otherwise undefined is returned.


If you want to find its index instead, use findIndex():

myArray.findIndex(x => x.id === '45');

From MDN:

The findIndex() method returns the index of the first element in the array that satisfies the provided testing function. Otherwise -1 is returned.


If you want to get an array of matching elements, use the filter() method instead:

myArray.filter(x => x.id === '45');

This will return an array of objects. If you want to get an array of foo properties, you can do this with the map() method:

myArray.filter(x => x.id === '45').map(x => x.foo);

Side note: methods like find() or filter(), and arrow functions are not supported by older browsers (like IE), so if you want to support these browsers, you should transpile your code using Babel (with the polyfill).

csdnceshi77
狐狸.fox This example uses ECMAScript 6 arrow function. In case of errors when using arrow functions, there are other ways out. See (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…) and (dmitripavlutin.com/…)
大约 2 年之前 回复
csdnceshi50
三生石@ - I did say "(Babel can also include polyfills for some things)" And agreed, polyfilling has moved on since copy-and-paste from MDN. :-)
2 年多之前 回复
weixin_41568174
from.. I don't think that it's a good idea to copy-paste polyfills from MDN into your code; instead, you should use npm packages with polyfills. And Babel does include polyfills for ES2015+ features, in the babel-polyfill package.
2 年多之前 回复
csdnceshi54
hurriedly% myArray.find(x => x.id === '45') it does not work on mac PC
2 年多之前 回复
csdnceshi60
℡Wang Yan For me, best answer so far. Doesn't need jQuery neither creating new auxiliar arrays.
接近 3 年之前 回复
weixin_41568183
零零乙 For multiple testing conditions would it therefore be something like: myArray.find(x => x.id === '45' && x.color == 'red').foo
大约 4 年之前 回复

As you are already using jQuery, you can use the grep function which is intended for searching an array:

var result = $.grep(myArray, function(e){ return e.id == id; });

The result is an array with the items found. If you know that the object is always there and that it only occurs once, you can just use result[0].foo to get the value. Otherwise you should check the length of the resulting array. Example:

if (result.length == 0) {
  // not found
} else if (result.length == 1) {
  // access the foo property using result[0].foo
} else {
  // multiple items found
}
csdnceshi54
hurriedly% I've created a tiny utility just for this where you can access with O(1) called super-array
大约 3 年之前 回复
csdnceshi67
bug^君 How can this be done in pure JavaScript?
3 年多之前 回复
csdnceshi69
YaoRaoLov This answer doesn't try to list all possible solutions, it only shows the simplest and most compatible solution in the situation specified in the question. IE 8 is still too common for advocating a solution that doesn't support it, when there is a solution that is as simple and does support it.
接近 6 年之前 回复
csdnceshi52
妄徒之命 Who cares about IE8 now. It's an edge case. Since you're answer is the selected as right one, a lot of novice JS devs won't know about filter because of your answer! You've a lot of responsibility :D
接近 6 年之前 回复
csdnceshi69
YaoRaoLov The filter method is not supported in older browsers like IE 8, so using a library like jQuery is still a good option if you need it to work for as many as possible.
接近 6 年之前 回复
csdnceshi69
YaoRaoLov What are you trying to accomplish with that? The pop method doesn't take a parameter, so it will just remove the last item from the array and return it.
大约 6 年之前 回复
csdnceshi64
游.程 once you have result, just do myArray.pop(result)
大约 6 年之前 回复
weixin_41568126
乱世@小熊 Indeed, your answer is absolutely correct with regard to the question as it is stated -- I just felt like pointing it out since it'll likely concern many readers who might otherwise miss an opportunity to do the right thing when they can (when the search property contains unique values).
6 年多之前 回复
csdnceshi69
YaoRaoLov Note that there is nothing in the question that specifically says that the id is unique, and that my answer doesn't do that assumption.
6 年多之前 回复
weixin_41568126
乱世@小熊 Many answers here provide the intended behavior when looking up unique values; you can essentially recognize them by the fact that they return or break from their loop early (or instruct a lower-level construct to stop iterating). See JaredPar's answer for a canonical example, and Aaronius's comment on that answer for the same insight. In general, people differentiate between "filter" and "find" functions in this way, but terminology varies. Though more efficient, this is still a linear search, so if you want to use a hash table, see Aaron Digulla's answer (beware of impl. details).
6 年多之前 回复
csdnceshi71
Memor.の Basically I always use === because it works exactly like == in other programming languages. I consider == to be non-existent in JavaScript.
接近 8 年之前 回复
csdnceshi71
Memor.の Well, if you're absolutely sure that both e.id and id will be strings, I suppose it's ok to use ==. But if you're not sure, you might face problems (since '' == 0 is true but '' === 0 is false). Not to mention === seems to be faster (stackoverflow.com/questions/359494/…).
接近 8 年之前 回复
csdnceshi69
YaoRaoLov Are there any issues when comparing a string to a string?
接近 8 年之前 回复
csdnceshi71
Memor.の It'd be safer to use === instead of ==, to avoid weird issues with JavaScript's == operator.
接近 8 年之前 回复

I think the easiest way would be the following, but it won't work on Internet Explorer 8 (or earlier):

var result = myArray.filter(function(v) {
    return v.id === '45'; // Filter out the appropriate one
})[0].foo; // Get result and access the foo property
csdnceshi76
斗士狗 This code will throw an error if there's no element with that id
3 年多之前 回复
weixin_41568174
from.. If you need support for IE8, just drop this in: stackoverflow.com/questions/7153470/…
7 年多之前 回复
csdnceshi51
旧行李 Zinov'yev: Yes it's a naive solution, I admit.
大约 9 年之前 回复
csdnceshi66
必承其重 | 欲带皇冠 So you're saying that it would be slower? Also, it will always scan the whole array, as far as I can see, whereas the for loop will terminate on the first match.
大约 9 年之前 回复
csdnceshi51
旧行李 Zinov'yev: Yes, there certainly are performance impacts with those ES5 array tools. A separate function is executed for each element, so it won't be really fast compared to a direct for loop.
大约 9 年之前 回复
csdnceshi66
必承其重 | 欲带皇冠 I'm curious, is there any performance advantage here compared to the usual for?
大约 9 年之前 回复

Underscore.js has a nice method for that:

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'},etc.]
obj = _.find(myArray, function(obj) { return obj.id == '45' })
csdnceshi71
Memor.の From the docs of _.find: "The function returns as soon as it finds an acceptable element, and doesn't traverse the entire list."
大约 5 年之前 回复
csdnceshi77
狐狸.fox If you are expecting only one object, then using findWhere would be more efficient as after finding one result, the search would not go any further.
大约 5 年之前 回复
csdnceshi55
~Onlooker For the record, Lo-Dash (which is often demonstrably more performant than Underscore) has a similar method. Docs here: lodash.com/docs#find
接近 7 年之前 回复

Another solution is to create a lookup object:

var lookup = {};
for (var i = 0, len = array.length; i < len; i++) {
    lookup[array[i].id] = array[i];
}

... now you can use lookup[id]...

This is especially interesting if you need to do many lookups.

This won't need much more memory since the IDs and objects will be shared.

weixin_41568131
10.24 This is the best solution as subsequent search of a specific id will require only O(1)
3 年多之前 回复
csdnceshi55
~Onlooker Thanks for your good answer, Is this a faster way? or is this way fast enough
大约 4 年之前 回复
csdnceshi62
csdnceshi62 Just to have this noted here: With this approach you convert the object to a hashmap so you have O(n) for the first lookup (since you need to convert first) and O(1) for each following one.
4 年多之前 回复
weixin_41568196
撒拉嘿哟木头 I have to admit that I probably copied the code from somewhere. When JavaScript was still interpreted, it was probably a small speed boost since local variables are faster than indirect references. Also, it should catch a couple of problems when you change the size of the array in the loop ... which no one ever does ;-)
4 年多之前 回复
csdnceshi70
笑故挽风 This is great. As a side note, is there any significant benefit to setting the array len in the first statement of the for loop? I usually write it like this: (var x = 0; x < array.length; x++). Hadn't seen that before and curious.
4 年多之前 回复
csdnceshi69
YaoRaoLov I created a array function based on @AaronDigulla's answer. It converts the array into an object, using a given key ( Usage: myArray.toObj('id'); ) --> Array.prototype.toObj=function(r){var t,o,n=this,e={};for(t=0,o=n.length;o>t;t++)e[n[t][r]]=n[t];return e;};
接近 5 年之前 回复
csdnceshi76
斗士狗 I love that approach. I was looking for away avoiding the constant O(N) for every lookup. I can live peacefully with the O(N) for updates since they don't occur as often as reads are happening :)
接近 5 年之前 回复
csdnceshi53
Lotus@ thanks you are right. The lookup replaces the array because the objects from the array are stored under their id in var lookup. To save memory i deleted the original array with array = [ ];
大约 5 年之前 回复
weixin_41568196
撒拉嘿哟木头 No, that doesn't make sense at all. The code above is useful if you need to do many lookups. If you look just once, then creating a lookup object is a waste of time.
大约 5 年之前 回复
csdnceshi53
Lotus@ Is using a break; in the loop a good option / improvement if you know there is only one object to find ?
大约 5 年之前 回复
weixin_41568126
乱世@小熊 As long as you don't rely on the order of properties: stackoverflow.com/questions/4886314/…
接近 6 年之前 回复
csdnceshi66
必承其重 | 欲带皇冠 this is smart. I can't imagine how others were convinced by looking all over the array for each use.
7 年多之前 回复
weixin_41568174
from.. Exactly what I was looking for. Funny how I was trying to over-complicate it by trying to loop through each time, removing each item from the list as I found it when I only needed to mutate the received data from CouchDB and get it into a format that is useful for my needs. +1 sir!
7 年多之前 回复

ECMAScript 2015 provides the find() method on arrays:

var myArray = [
 {id:1, name:"bob"},
 {id:2, name:"dan"},
 {id:3, name:"barb"},
]

// grab the Array item which matchs the id "2"
var item = myArray.find(item => item.id === 2);

// print
console.log(item.name);

It works without external libraries. But if you want older browser support you might want to include this polyfill.

</div>
weixin_41568127
?yb? Like the answer states there is a polyfill if you want older browser support. Likewise it is easy to rewrite using the older syntax.
大约 2 年之前 回复
weixin_41568126
乱世@小熊 This solution is for ES6 and it doesn't compatible with IE browser.
大约 2 年之前 回复
weixin_41568127
?yb? If you want to be sure you can alway null-check, which will be really easy with optional chaining: myArray.find(d => d.id === 45)?.foo.
2 年多之前 回复
csdnceshi66
必承其重 | 欲带皇冠 if the .find() returns undefined, then your optimization throws an error. So this solution is can be used only in cases where a match is guaranteed.
2 年多之前 回复
weixin_41568127
?yb? answer is currently the most up to date in the thread.
3 年多之前 回复
csdnceshi60
℡Wang Yan This can be simplified to myArray.find(d=>d.id===45).foo;.
3 年多之前 回复
csdnceshi63
elliott.david Probably cause it still seems very experimental and not many browsers support it, developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
6 年多之前 回复

Building on the accepted answer:

jQuery:

var foo = $.grep(myArray, function(e){ return e.id === foo_id})
myArray.pop(foo)

Or CoffeeScript:

foo = $.grep myArray, (e) -> e.id == foo_id
myArray.pop foo

A generic and more flexible version of the findById function above:

// array = [{key:value},{key:value}]
function objectFindByKey(array, key, value) {
    for (var i = 0; i < array.length; i++) {
        if (array[i][key] === value) {
            return array[i];
        }
    }
    return null;
}

var array = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];
var result_obj = objectFindByKey(array, 'id', '45');

You can do this even in pure JavaScript by using the in built "filter" function for arrays:

Array.prototype.filterObjects = function(key, value) {
    return this.filter(function(x) { return x[key] === value; })
}

So now simply pass "id" in place of key and "45" in place of value, and you will get the full object matching an id of 45. So that would be,

myArr.filterObjects("id", "45");
csdnceshi52
妄徒之命 Don't modify objects you don't own.
4 年多之前 回复

Iterate over any item in the array. For every item you visit, check that item's id. If it's a match, return it.

If you just want teh codez:

function getId(array, id) {
    for (var i = 0, len = array.length; i < len; i++) {
        if (array[i].id === id) {
            return array[i];
        }
    }
    return null; // Nothing found
}

And the same thing using ECMAScript 5's Array methods:

function getId(array, id) {
    var obj = array.filter(function (val) {
        return val.id === id;
    });

    // Filter returns an array, and we just want the matching item.
    return obj[0];
}
共29条数据 1 3 尾页
立即提问
相关内容推荐