Javascript Equivalent to C# LINQ Select

前端 未结 12 1519
孤街浪徒
孤街浪徒 2020-12-02 06:33

Following this question here :

Using the checked binding in knockout with a list of checkboxes checks all the checkboxes

I\'ve c

12条回答
  •  南方客
    南方客 (楼主)
    2020-12-02 06:58

    Yes, Array.map() or $.map() does the same thing.

    //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/

    Since array.map isn't supported in older browsers, I suggest that you stick with the jQuery method.

    If you prefer the other one for some reason you could always add a polyfill for old browser support.

    You can always add custom methods to the array prototype as well:

    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;
    });
    

    An extended version that uses the function constructor if you pass a string. Something to play around with perhaps:

    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/

    Update:

    Since this has become such a popular answer, I'm adding similar my where() + firstOrDefault(). These could also be used with the string based function constructor approach (which is the fastest), but here is another approach using an object literal as filter:

    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;
    };
    

    Usage:

    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' }); 
    

    Here is a jsperf test to compare the function constructor vs object literal speed. If you decide to use the former, keep in mind to quote strings correctly.

    My personal preference is to use the object literal based solutions when filtering 1-2 properties, and pass a callback function for more complex filtering.

    I'll end this with 2 general tips when adding methods to native object prototypes:

    1. Check for occurrence of existing methods before overwriting e.g.:

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

    2. If you don't need to support IE8 and below, define the methods using Object.defineProperty to make them non-enumerable. If someone used for..in on an array (which is wrong in the first place) they will iterate enumerable properties as well. Just a heads up.

提交回复
热议问题