在JavaScript中基本实现“where”子句的最佳方法是什么?

15

我正在尝试解析发送给我的一些JSON数据,它们都是以下格式的

[{key:value},{key2:value2}, ... ]

如何最好地获取这个对象中 key2 的值?有没有一种不需要使用 for 循环的方法来实现?


为什么你不想使用for循环呢? - meder omuraliev
20
有人对Linq上瘾了! - Blindy
@Earlz 你为什么要避免使用for循环?是出于性能方面的考虑吗?另外,你用什么来解析JSON? - rsbarro
1
@rsb,我只是想要比for循环更简洁的东西。 - Earlz
好的,但是某些时候会使用for/while循环。对我来说,对象数组似乎不是最好的数据结构,如果你有相同键的对象,你想返回找到的第一个键的值还是所有值(考虑[{foo:'bar'},{foo:'baz'},{bar:'foo'}])? - vol7ron
显示剩余2条评论
11个回答

9

作为参考,我的最终结果看起来像 var value2 = _.detect(data, function(d) { return d.key2 != undefined; }).key2; - Earlz
4
这不需要为一个特定情况加载整个库(虽然很小)吗? - vol7ron
1
@vol7ron 是的。但我敢打赌,一旦你在一个地方使用它,你会看到其他地方也可以用它。 - Paul Phillips
1
它非常轻量级,所以这很可能是真的。 - vol7ron
2
不需要整个库,只需在数组上执行filter() - Mladen B.
显示剩余2条评论

8

不是很难,但可以创建一个函数来实现。然而,这确实需要一个 for 循环。

为了完整起见,以下是该函数:

function selectWhere(data, propertyName) {
    for (var i = 0; i < data.length; i++) {
        if (data[i][propertyName] !== null) return data[i][propertyName];
    }
    return null;
}

使用方法:

var key2value = selectWhere(data, "key2");

这个代码只有几个我不喜欢的地方:1) 使用了 null2) 函数名为 selectWhere;除此之外,做得很好,但是考虑使用反向 for 循环 - vol7ron

7

Javascript数组提供了一些方法,可以在不用编写for循环的情况下找到符合条件的条目。

您只需提供所需的条件。一个简洁和方便的方法是使用箭头(或“lambda”)函数。在您的情况下,您正在查找具有特定键的数组条目,因此箭头函数可能如下所示:

e => e.hasOwnProperty("key2")

跟随其他人的做法,让我们从以下假设开始:

var arr = [{key:"value"}, {key2:"value2"}, {key3:"value3"}]

如果你期望数组中最多只有一个元素具有你想要的键,你可以使用find()函数。它会测试每个数组成员,直到找到其中一个满足你的条件,并返回它。如果没有满足条件的元素,则会返回undefined
var foundentry = arr.find(e => e.hasOwnProperty("key2"))

如果你要查找的键有多个条目,那么使用filter()而不是find()。它会返回符合条件的条目数组。


foundentry将要么是未定义的,要么是你要查找的{key2:"value2"},并且可以从中提取value2

var foundarray = arr.filter(e => e.hasOwnProperty("key2"))

这是目前最好的答案。在2011年,可能还没有可用的查找和过滤方法。 - Harlan

3

jQuery grep()是一个很好的类似于Where子句的模拟器:

var array = [{key:1},{key:2}, {key:3}, {key:4}, {key:5}];

var filtered = jQuery.grep(array, function( item, index ) {
  return ( item.key !== 4 && index > 1 );
});

你的筛选数组将包含两个元素,
 [{key:3}, {key:5}]

2

你不能使用数组来做到这一点,但是你可以用它创建一个类似于关联数组的对象。一旦你创建了它,你就可以像哈希表一样使用它。

var arr = [{key:value},{key2:value2}, ... ], obj = {};

for (var i = 0, len = arr.length; i < len; i++) {
    $.extend(obj, arr[i]);
}

console.log(obj.key2); // value2

1

这里有一个原型化数组对象的示例。注意:这只是一个示例 - find 不是这个函数的好名称,而且这可能并不适用于所有的数组。

相反地,考虑只使用函数定义并创建一个类似于 getObjVal 的函数,调用方式类似于 LaurenT 的答案:getObjVal(arr,'propName')

给定


var arr = [{key:'value'},{key2:'value2'}];

定义


// for-loop example
Array.prototype.find = function (prop){
                          for(var i=this.length; i--; )
                             if (typeof this[i][prop] !== 'undefined')
                                return this[i][prop];
                          return undefined;
                       }

// for-each loop example
Array.prototype.find = function (prop){
                          for (var i in this)
                             if ( this.hasOwnProperty(i) && typeof this[i][prop] !== "undefined" ) 
                                return this[i][prop];
                          return undefined;
                       }

使用方法


console.log( arr.find('key2') );  // 'value2'
console.log( arr.find('key3') );  // undefined

1

使用.filter()方法来操作此对象数组,例如在您的情况下:

var objArray = [{key:"Hello"},{key2:"Welcome"} ];
var key2Value=objArray.filter(x=>x.key2)[0].key2;


这将是一个SELECT而不是WHERE。 - TheQult

0

正则表达式 - 无需循环:

var key2Val = jsonString.match(/\{key2:[^\}]+(?=\})/)[0].substring("{key2:".length);

0

嗨。您可以使用lodash库的.reduce().transform()函数来实现此操作。Lodash比underscore更模块化(Underscore约5kb,Lodash约17kb),但通常更轻便,因为您只需要包含所需的特定模块 (请参见:https://news.ycombinator.com/item?id=9078590 进行讨论)。对于此演示,我将导入整个模块(通常在后端不是问题): 我编写了这些代码片段以处理数字和非数字参数的两种情况。

https://lodash.com/docs#reduce

https://lodash.com/docs#transform

引入 lodash:

var _ = require('lodash');

使用 _.reduce() 转换为 where 子句:

var delim = ' WHERE ', where = _.isEmpty(options) ? '' : _.reduce(options, function(r, v, k) {
    var w = r + delim + k + '=' + (_.isNumber(v) ? v : ("'" + v + "'"));
    delim = ' AND ';
    return w;
}, '');

将_.transform()应用于where子句:

var where = _.isEmpty(options) ? '' : ' WHERE ', delim = '';
_.transform(options, function(r, v, k) {
        where = where + delim + k + '=' + (_.isNumber(v) ? v : ("'" + v + "'"));
        delim = ' AND ';
    });

希望这有所帮助。

0

顶尖答案完成了任务。 这是使用lodash(大部分与underscore相同)的单行版本:

var result = _.filter(data, _.partialRight(_.has, 'key2'));

在lodash中,select只是filter的别名。我将填充了对象的数据数组传递给它。我使用_.has作为过滤函数,因为它正好做我们想要的事情:检查属性是否存在。 _.has需要两个参数:
_.has(object, path)

由于_.has需要两个参数,而我知道其中一个始终是常量(路径参数)。因此,我使用_.partialRight函数来附加常量key2_.partialRight返回一个新函数,该函数期望一个参数:要检查的对象。新函数检查obj.key2是否存在。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接