Javascript實現Linq查詢方式


 

    Linq是.net平台一個重要的技術,全稱Language Integrated Query通過構建快速查詢語句,可快速從數據庫或集合中篩選數據集、以查詢數據庫相同的方式操作內存數據。

    在ECMAScript 5th以后的版本中,Javascript實現了有限的有限的Linq查詢方式,包括forEach, every, some, filter, map, reduce and reduceRight.

     首先需要說明,以上這些方法並不是跨瀏覽器的,對版本有相應的限制。我們知道Linq的對象需要實現Enumerable接口,本篇文章主要介紹使用JS模擬實現C# 中的Linq查詢,包括 聚集查詢、迭代查詢、條件查詢、構建Selector查詢器等。

Javascript本質上並不支持類的繼承,通過屬性的繼承可實現類的面向對象的功能,所以這也被認為是面向對象的一種方式,這就意味着可以使用它的屬性構建更多面向對象的接口。例如Array,它是繼承自Array.prototype 。如果更改了Array.prototype,那么基於這個屬性繼承的數組必然會變化有了這些依據后開始構建我們的Linq功能。

舉個例子,JS API不支持union方法,但支持concat方法合並數據。

Array.prototype.union
Array.prototype.union = Array.prototype.concat; 

先來看看一個.NET下的簡單查詢方式

var someArray = new int[] { 1, 2, 3, 4 };
var otherArray = someArray.Select(t => t * 2);   
c# Select

在C#下使用查詢數據時使用的是Select,使用一個 Delegate 構建查詢。在這個例子中,我們使用了  t => t * 2 是一個 Lambda表達式。 將這個功能嫁接到JS下,定義一個function(){}

JS下的Select查詢可以是這樣

var someArray = [1, 2, 3, 4];
var otherArray = someArray.select(function (t) { return t * 2 }); 
JS Select

以下我們將一一實現JS的 比較(EqualityComparer)、排序(SortComparer)、條件(Predicate)、查詢器(Selector)

  • Javascript Linq 查詢器

 Select

遍歷元素下的每一個元素,調用JS.Call方法返回數據。

Array.prototype.select = Array.prototype.map || function (selector, context) {
    context = context || window;
    var arr = [];
    var l = this.length;
    for (var i = 0; i < l; i++)
        arr.push(selector.call(context, this[i], i, this));
    return arr;
};


var arr = [1, 2, 3, 4, 5];
var doubled = arr.select(function(t){ return t * 2 }); 
Select

SelectMany

 

SelectMany
Array.prototype.selectMany = function (selector, resSelector) {
    resSelector = resSelector || function (i, res) { return res; };
    return this.aggregate(function (a, b, i) {
        return a.concat(selector(b, i).select(function (res) { return resSelector(b, res) }));
    }, []);
}; 

var arr = [{Name:"A", Values:[1, 2, 3, 4]}, {Name:"B", Values:[5, 6, 7, 8]}];  
var res1 = arr.selectMany(function(t){ return t.Values });  
var res2 = arr.selectMany(function(t){ return t.Values }, function(t, u){ return {Name:t.Name, Val:u}}); 

 

Take

Array.prototype.take = function (c) {
    return this.slice(0, c);
};  

var arr = [1, 2, 3, 4, 5]; 
var res = arr.take(2);
Take

Skip

跳過指定數后返回集合數據,使用slice。

Array.prototype.skip = function (c) {
    return this.slice(c);
}; 

var arr = [1, 2, 3, 4, 5]; 
var res = arr.skip(2);  
Skip

First

返回序列的第一個元素,如果沒有元素,可以指定一個默認元素。

Array.prototype.first = function (predicate, def) {
    var l = this.length;
    if (!predicate) return l ? this[0] : def == null ? null : def;
    for (var i = 0; i < l; i++)
        if (predicate(this[i], i, this))
            return this[i];
    return def == null ? null : def;
}; 

var arr = [1, 2, 3, 4, 5];
var t1 = arr.first();  
var t2 = arr.first(function(t){ return t > 2 }); 
var t3 = arr.first(function(t){ return t > 10 }, 10); //默認值是10
First

Union

合並兩個集合中的數據,使用concat,不合並重復數據。

Array.prototype.union = function (arr) {
    return this.concat(arr).distinct();
};  

var arr1 = [1, 2, 3, 4, 5]; 
var arr2 = [5, 6, 7, 8, 9];
var res = arr1.union(arr2);  
Union

Distinct

找出不重復的數據。當有重復元素是只push一個元素進集合。

Array.prototype.distinct = function (comparer) {
    var arr = [];
    var l = this.length;
    for (var i = 0; i < l; i++) {
        if (!arr.contains(this[i], comparer))
            arr.push(this[i]);
    }
    return arr;
};    


var arr1 = [1, 2, 2, 3, 3, 4, 5, 5];   
var res1 = arr.distinct();  // [1, 2, 3, 4, 5]

var arr2 = [{Name:"A", Val:1}, {Name:"B", Val:1}];
var res2 = arr2.distinct(function(a, b){ return a.Val == b.Val }); //返回[{Name:"A", Val:1}] 
Distinct

IndexOf

查找指定的值第一次出現的位置。

Array.prototype.indexOf = Array.prototype.indexOf || function (o, index) {
    var l = this.length;
    for (var i = Math.max(Math.min(index, l), 0) || 0; i < l; i++)
        if (this[i] === o) return i;
    return -1;
};  

var arr = [1, 2, 3, 4, 5];
var index = arr.indexOf(2);  // 1 
IndexOf

Remove

從集合中移除指定元素。

Array.prototype.remove = function (item) {
    var i = this.indexOf(item);
    if (i != -1)
        this.splice(i, 1);
}; 

var arr = [1, 2, 3, 4, 5];
arr.remove(2);   // [1, 3, 4, 5]
Remove

OrderBy

Array.prototype.orderBy = function (selector, comparer) {
    comparer = comparer || DefaultSortComparer;
    var arr = this.slice(0);
    var fn = function (a, b) {
        return comparer(selector(a), selector(b));
    };

    arr.thenBy = function (selector, comparer) {
        comparer = comparer || DefaultSortComparer;
        return arr.orderBy(DefaultSelector, function (a, b) {
            var res = fn(a, b);
            return res === 0 ? comparer(selector(a), selector(b)) : res;
        });
    };

    arr.thenByDescending = function (selector, comparer) {
        comparer = comparer || DefaultSortComparer;
        return arr.orderBy(DefaultSelector, function (a, b) {
            var res = fn(a, b);
            return res === 0 ? -comparer(selector(a), selector(b)) : res;
        });
    };

    return arr.sort(fn);
}; 





var arr = [{Name:"A", Val:1}, {Name:"a", Val:2}, {Name:"B", Val:1}, {Name:"C", Val:2}];

var res1 = arr.orderBy(function(t){ return t.Name });   

var res2 = arr.orderBy(function(t){ return t.Name }, function(a, b){
    if(a.toUpperCase() > b.toUpperCase()) return 1;
    if(a.toUpperCase() < b.toUpperCase()) return -1;
    return 0;
});    
OrderBy

OrderByDescending

Array.prototype.orderByDescending = function (selector, comparer) {
    comparer = comparer || DefaultSortComparer;
    return this.orderBy(selector, function (a, b) { return -comparer(a, b) });
};

var arr = [{Name:"A", Val:1}, {Name:"a", Val:2}, {Name:"B", Val:1}, {Name:"C", Val:2}];
var res = arr.orderByDescending(function(t){ return t.Name });   
OrderByDescending

GroupBy

Array.prototype.groupBy = function (selector, comparer) {
    var grp = [];
    var l = this.length;
    comparer = comparer || DefaultEqualityComparer;
    selector = selector || DefaultSelector;

    for (var i = 0; i < l; i++) {
        var k = selector(this[i]);
        var g = grp.first(function (u) { return comparer(u.key, k); });

        if (!g) {
            g = [];
            g.key = k;
            grp.push(g);
        }

        g.push(this[i]);
    }
    return grp;
};  


var arr = [{Name:"A", Val:1}, {Name:"B", Val:1}, {Name:"C", Val:2}, {Name:"D", Val:2}]; 
var res = arr.groupBy(function(t){ return t.Val }); 
// [[{Name:"A", Val:1}, {Name:"B", Val:1}], [{Name:"C", Val:2}, {Name:"D", Val:2}]] 

res.forEach(function(t){ 
    console.log("Key: " + t.key, "Length: " + t.length); 
});   
GroupBy

 

  • Javascript Linq 聚合

Min

Array.prototype.min = function (s) {
    s = s || DefaultSelector;
    var l = this.length;
    var min = s(this[0]);
    while (l-- > 0)
        if (s(this[l]) < min) min = s(this[l]);
    return min;
};  


var arr1 = [1, 2, 3, 4, 5, 6, 7, 8];
var min1 = arr.min();  // 1 

var arr2 = [{Name:"A", Val:1}, {Name:"B", Val:2}];
var min2 = arr2.min(function(t){ return t.Val });   // 1 
Min

Max

Array.prototype.max = function (s) {
    s = s || DefaultSelector;
    var l = this.length;
    var max = s(this[0]);
    while (l-- > 0)
        if (s(this[l]) > max) max = s(this[l]);
    return max;
};  

var arr1 = [1, 2, 3, 4, 5, 6, 7, 8];
var max1 = arr.max();  // 8 

var arr2 = [{Name:"A", Val:1}, {Name:"B", Val:2}];
var max2 = arr2.max(function(t){ return t.Val });   // 2  
Max

Sum

Array.prototype.sum = function (s) {
    s = s || DefaultSelector;
    var l = this.length;
    var sum = 0;
    while (l-- > 0) sum += s(this[l]);
    return sum;
}; 

var arr1 = [1, 2, 3, 4, 5, 6, 7, 8];
var sum1 = arr.sum();  // 36 

var arr2 = [{Name:"A", Val:1}, {Name:"B", Val:2}];
var sum2 = arr2.sum(function(t){ return t.Val });   // 3 
Sum

 

  • Javascript Linq 條件查詢

Where

Array.prototype.where = Array.prototype.filter || function (predicate, context) {
    context = context || window;
    var arr = [];
    var l = this.length;
    for (var i = 0; i < l; i++)
        if (predicate.call(context, this[i], i, this) === true) arr.push(this[i]);
    return arr;
}; 

var arr = [1, 2, 3, 4, 5];
var res = arr.where(function(t){ return t > 2 }) ;  // [3, 4, 5] 
Where

Any

Array.prototype.any = function (predicate, context) {
    context = context || window;
    var f = this.some || function (p, c) {
        var l = this.length;
        if (!p) return l > 0;
        while (l-- > 0)
            if (p.call(c, this[l], l, this) === true) return true;
        return false;
    };
    return f.apply(this, [predicate, context]);
};  


var arr = [1, 2, 3, 4, 5];
var res1 = arr.any();  // true
var res2 = arr.any(function(t){ return t > 5 });  // false 
Any

All

Array.prototype.all = function (predicate, context) {
    context = context || window;
    predicate = predicate || DefaultPredicate;
    var f = this.every || function (p, c) {
        return this.length == this.where(p, c).length;
    };
    return f.apply(this, [predicate, context]);
};  

var arr = [1, 2, 3, 4, 5];
var res = arr.all(function(t){ return t < 6 });  // true 
All

Contains

Array.prototype.contains = function (o, comparer) {
    comparer = comparer || DefaultEqualityComparer;
    var l = this.length;
    while (l-- > 0)
        if (comparer(this[l], o) === true) return true;
    return false;
}; 

var arr1 = [1, 2, 3, 4, 5]; 
var res1 = arr.contains(2);  // true 

var arr2 = [{Name:"A", Val:1}, {Name:"B", Val:1}]; 
var res2 = arr2.contains({Name:"C", Val:1}, function(a, b){ return a.Val == b.Val }) ;  // true 
Contains

 

  • Javasciprt Linq 迭代

ForEach

Array.prototype.forEach = Array.prototype.forEach || function (callback, context) {
    context = context || window;
    var l = this.length;
    for (var i = 0; i < l; i++)
        callback.call(context, this[i], i, this);
};  

var arr = [1, 2, 3, 4, 5];
arr.forEach(function(t){ if(t % 2 ==0) console.log(t); });   
ForEach

 

DefaultIfEmpty

Array.prototype.defaultIfEmpty = function (val) {
    return this.length == 0 ? [val == null ? null : val] : this;
};  

var arr = [1, 2, 3, 4, 5];
var res = arr.where(function(t){ return t > 5 }).defaultIfEmpty(5);  // [5]  
DefaultIfEmpty

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM