Javascript 相当于 C# LINQ Select

2022-08-30 02:04:26

在这里遵循这个问题:

在挖空中使用选中的绑定和复选框列表可检查所有复选框

我使用挖空创建了一些复选框,允许从数组中进行选择。工作小提琴取自上面的帖子:

http://jsfiddle.net/NsCXJ/

有没有一种简单的方法来创建一个仅包含水果ID的数组?

我对C#更熟悉,我会做一些类似以下方面的事情:selectedFruits.select(fruit=>fruit.id);

有没有一些方法/现成的函数来做类似的事情与javascript / jquery?或者最简单的选择是遍历列表并创建第二个数组?我打算以JSON格式将数组发布回服务器,因此我试图最小化发送的数据。


答案 1

是的,Array.map()$.map() 做同样的事情。

//array.map:
var ids = this.fruits.map(function(v){
    return v.Id;
});

//jQuery.map:
var ids2 = $.map(this.fruits, function (v){
    return v.Id;
});

console.log(ids, ids2);

http://jsfiddle.net/NsCXJ/1/

由于旧版浏览器不支持 array.map,我建议您坚持使用 jQuery 方法。

如果您出于某种原因更喜欢另一个,您可以随时为旧浏览器支持添加polyfill。

您也可以始终将自定义方法添加到数组原型中:

Array.prototype.select = function(expr){
    var arr = this;
    //do custom stuff
    return arr.map(expr); //or $.map(expr);
};

var ids = this.fruits.select(function(v){
    return v.Id;
});

如果传递字符串,则使用函数构造函数的扩展版本。也许可以玩一些事情:

Array.prototype.select = function(expr){
    var arr = this;

    switch(typeof expr){

        case 'function':
            return $.map(arr, expr);
            break;

        case 'string':

            try{

                var func = new Function(expr.split('.')[0], 
                                       'return ' + expr + ';');
                return $.map(arr, func);

            }catch(e){

                return null;
            }

            break;

        default:
            throw new ReferenceError('expr not defined or not supported');
            break;
    }

};

console.log(fruits.select('x.Id'));

http://jsfiddle.net/aL85j/

更新:

由于这已经成为一个如此流行的答案,我正在添加类似的我的+。这些也可以与基于字符串的函数构造函数方法一起使用(这是最快的),但下面是另一种使用对象文本作为过滤器的方法:where()firstOrDefault()

Array.prototype.where = function (filter) {

    var collection = this;

    switch(typeof filter) { 

        case 'function': 
            return $.grep(collection, filter); 

        case 'object':
            for(var property in filter) {
              if(!filter.hasOwnProperty(property)) 
                  continue; // ignore inherited properties

              collection = $.grep(collection, function (item) {
                  return item[property] === filter[property];
              });
            }
            return collection.slice(0); // copy the array 
                                      // (in case of empty object filter)

        default: 
            throw new TypeError('func must be either a' +
                'function or an object of properties and values to filter by'); 
    }
};


Array.prototype.firstOrDefault = function(func){
    return this.where(func)[0] || null;
};

用法:

var persons = [{ name: 'foo', age: 1 }, { name: 'bar', age: 2 }];

// returns an array with one element:
var result1 = persons.where({ age: 1, name: 'foo' });

// returns the first matching item in the array, or null if no match
var result2 = persons.firstOrDefault({ age: 1, name: 'foo' }); 

下面是一个 jsperf 测试,用于比较函数构造函数与对象文本速度。如果您决定使用前者,请记住正确引用字符串。

我个人倾向于在筛选 1-2 个属性时使用基于对象文本的解决方案,并传递回调函数以进行更复杂的筛选。

在向本机对象原型添加方法时,我将以 2 个常规提示结束本文:

  1. 在覆盖之前检查现有方法的出现,例如:

    if(!Array.prototype.where) { Array.prototype.where = ...

  2. 如果不需要支持 IE8 及更低版本,请使用 Object.defineProperty 定义方法,使它们不可枚举。如果有人在数组上使用(这首先是错误的),他们也会迭代可枚举属性。只是一个抬头。for..in


答案 2

我知道这是一个迟到的答案,但它对我有用!只是为了完成,使用该函数,您可以模拟linq。$.grepwhere()

Linq:

var maleNames = people
.Where(p => p.Sex == "M")
.Select(p => p.Name)

Javascript:

// replace where  with $.grep
//         select with $.map
var maleNames = $.grep(people, function (p) { return p.Sex == 'M'; })
            .map(function (p) { return p.Name; });