我有一个数组:

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

我无法更改阵列的结构。我收到了一个45的id,我想得到数组中该对象的“bar”。

如何在JavaScript或使用jQuery实现这一点?


当前回答

表演

今天2020.06.20我在Chrome 81.0、Firefox 77.0和Safari 13.1上对MacOs High Sierra进行了测试,以获得所选的解决方案。

使用预先计算的解决方案的结论

具有预计算(K,L)的解决方案比其他解决方案(快得多),不会与它们进行比较-可能它们使用了一些特殊的内置浏览器优化

令人惊讶的是,基于Map(K)的Chrome和Safari解决方案比基于对象{}(L)的解决方案快得多令人惊讶的是,Safari上基于对象{}的小型阵列解决方案(L)比传统的(E)慢令人惊讶的是,Firefox上基于Map(K)的小阵列解决方案比传统的(E)慢

搜索对象始终存在时的结论

使用传统for(E)的解决方案对于小阵列最快,对于大阵列最快对于大型阵列,使用缓存(J)的解决方案是最快的,而对于小型阵列,则是中等速度基于find(A)和findIndex(B)的解决方案对于小阵列很快,对于大阵列则很快基于$.map(H)的解决方案在小型阵列上是最慢的基于reduce(D)的解决方案在大型阵列上最慢

搜索对象从不存在时的结论

基于传统for(E)的解决方案在小型和大型阵列上都是最快的(除了Chrome小型阵列,后者速度第二快)基于reduce(D)的解决方案在大型阵列上最慢使用缓存(J)的解决方案是中等速度的,但如果我们将具有空值的键也保存在缓存中,则可以加快速度(这里没有这样做,因为我们希望避免在搜索许多不存在的键时在缓存中无限制地消耗内存)

细节

对于解决方案

无需预先计算:ABCDEFGH我J(J解决方案使用“内部”缓存,其速度取决于搜索元素重复的频率)带有预先计算KL

我进行了四次测试。在测试中,我希望在10次循环迭代中找到5个对象(对象ID在迭代过程中不会改变)-所以我调用测试方法50次,但只有前5次具有唯一的ID值:

小数组(10个元素)和搜索对象始终存在-您可以在此处执行大数组(10k个元素)和搜索对象始终存在-您可以在此处执行小数组(10个元素)和搜索对象从不存在-您可以在此处执行大数组(10k个元素)和搜索对象从不存在-您可以在这里执行

测试代码如下

函数A(arr,id){返回arr.find(o=>o.id==id);}函数B(arr,id){设idx=arr.findIndex(o=>o.id==id);返回arr[idx];}函数C(arr,id){返回arr.filter(o=>o.id==id)[0];}函数D(arr,id){return arr.reduce((a,b)=>(a.id==id&&a)||(b.id==id&&b));}函数E(arr,id){对于(var i=0;i<arr.length;i++)如果(arr[i].id==id)返回arr[i];返回null;}函数F(arr,id){var retObj={};$.each(arr,(索引,obj)=>{如果(obj.id==id){retObj=对象;return false;}});返回retObj;}函数G(arr,id){return$.grep(arr,e=>e.id==id)[0];}函数H(arr,id){return$.map(myArray,函数(val){返回val.id==id?val:空;})[0];}函数I(arr,id){return _.find(arr,o=>o.id==id);}设J=(()=>{let cache=new Map();返回函数J(arr,id,el=null){返回cache.get(id)||(el=arr.find(o=>o.id==id),cache.set(id,el),el);}})();函数K(arr,id){return mapK.get(id)}函数L(arr,id){返回mapL[id];}// -------------//测试// -------------console.log('查找id=5');myArray=[…Array(10)].map((x,i)=>({'id':`${i}`,'foo':`bar_${i}`));const mapK=新地图(myArray.Map(el=>[el.id,el]));常量mapL={};myArray.forEach(el=>mapL[el.id]=el);[A,B,C,D,E,F,G,H,I,J,K,L].forEach(F=>console.log(`${F.name}:${JSON.stringify(F(myArray,'5'))}`));console.log('hole array',JSON.stringify(myArray));<script src=“https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js“></script><script src=“https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js“></script>此代码段仅显示经过测试的代码

搜索对象始终存在的小数组的Chrome测试结果示例

其他回答

即使在纯JavaScript中,也可以通过对数组使用内置的“filter”函数来实现这一点:

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

所以现在只需用“id”代替key,用“45”代替value,就会得到与id 45匹配的完整对象。那就是,

myArr.filterObjects("id", "45");

只要浏览器支持ECMA-262,第5版(2009年12月),这应该可以工作,几乎只有一行:

var bFound = myArray.some(function (obj) {
    return obj.id === 45;
});

我真的很喜欢Aaron Digulla提供的答案,但需要保留我的对象数组,以便稍后可以迭代。所以我把它改成

var索引器={};对于(var i=0;i<array.length;i++){索引器[array[i].id]=parseInt(i);}//然后可以使用以下命令访问数组中的对象财产数组[索引器[id]].properties

正如其他人所指出的,.find()是在数组中查找一个对象的方法。但是,如果无法使用此方法找到对象,则程序将崩溃:const myArray=[{'id':'73','o':'bar'},{'id':'45','o':'bar'}];const res=myArray.find(x=>x.id=='100').foo;//噢!/*错误:“Uncaught TypeError:无法读取未定义的属性'foo'”或在较新的chrome版本中:Uncaught TypeError:无法读取未定义的的财产(读取“foo”)*/

这可以通过在使用.foo之前检查.find()的结果是否已定义来解决。Modern JS允许我们通过可选链接轻松完成这一点,如果找不到对象,则返回undefined,而不是崩溃代码:

const myArray=[{'id':'73','o':'bar'},{'id':'45','o':'bar'}];const res=myArray.find(x=>x.id=='100')?。foo;//没有错误!console.log(res);//找不到对象时未定义

此解决方案也可能有帮助:

Array.prototype.grep = function (key, value) {
    var that = this, ret = [];
    this.forEach(function (elem, index) {
        if (elem[key] === value) {
            ret.push(that[index]);
        }
    });
    return ret.length < 2 ? ret[0] : ret;
};
var bar = myArray.grep("id","45");

我将其设置为$.grep,如果找到一个对象,函数将返回该对象,而不是数组。