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[] { , , ,  };
var otherArray = someArray.Select(t => t * );

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

Javascript实现Linq查询方式的更多相关文章

  1. xamarin studio And linq 查询方式分析

    在 Windows 操作系统可以正常读取网络上的 https 数据流,在 Linux 操作系统中会失败:http://www.cnblogs.com/skyivben/archive/2012/03/ ...

  2. LINQ查询数组里面是否包含某值

    #region linq to 数组            //定义数组,并初始化            string [] array = new string []{"Juan" ...

  3. C#高级知识点概要(3) - 特性、自动属性、对象集合初始化器、扩展方法、Lambda表达式和Linq查询

    1.特性(Attributes) 特性(Attributes),MSDN的定义是:公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型.字段.方法 ...

  4. C#基础:LINQ 查询函数整理

    1.LINQ 函数   1.1.查询结果过滤 :where() Enumerable.Where() 是LINQ 中使用最多的函数,大多数都要针对集合对象进行过滤,因此Where()在LINQ 的操作 ...

  5. Linq查询表达式

    目录 1. 概述 2. from子句 3. where子句 4. select子句 5. group子句 6. into子句 7. 排序子句 8. let子句 9. join子句 10. 小结 1. ...

  6. LINQ 查询表达式(C# 编程指南)

    语言集成查询 (LINQ) 是一组技术的名称,这些技术建立在将查询功能直接集成到 C# 语言(以及 Visual Basic 和可能的任何其他 .NET 语言)的基础上.  借助于 LINQ,查询现在 ...

  7. LINQ查询返回DataTable类型

    个人感觉Linq实用灵活性很大,参考一篇大牛的文章LINQ查询返回DataTable类型 http://xuzhihong1987.blog.163.com/blog/static/267315872 ...

  8. atitit. 集合groupby 的实现(2)---自定义linq查询--java .net php

    atitit.  集合groupby 的实现(2)---自定义linq查询--java .net php 实现方式有如下 1. Linq的实现原理流程(ati总结) 1 2. groupby  与 事 ...

  9. Linq查询简介

    查询是一种从数据源检索数据的表达式. 查询通常用专门的查询语言来表示. 随着时间的推移,人们已经为各种数据源开发了不同的语言:例如,用于关系数据库的 SQL 和用于 XML 的 XQuery. 因此, ...

随机推荐

  1. POJ 1837 Balance

    Balance Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 9240 Accepted: 5670 Description G ...

  2. Stockbroker Grapevine(floyd)

    Stockbroker Grapevine Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 28231   Accepted: ...

  3. nginx-upload-module模块实现文件断点续传

    导读 每当我们想简单的实现文件上传功能,而又不使用其他的语言(比如PHP.Java),或者想实现文件的断点续传.这个时候Nginx的一个模块nginx-upload-module就能满足我们的需求. ...

  4. Class Methods & Variables

    When calling an instance method like withdraw_securely, the syntax generally looks something like th ...

  5. django-cms 代码研究(五)深入(代码结构)

    前言: 前戏已经做得比较充分了,下面我们开始步入正题. 代码结构: cms |--admin (猜测是admin界面的二次开发和改良) |--cache (猜测是缓存机制的处理) |--extensi ...

  6. Longest Consecutive Sequence

    Given an unsorted array of integers, find the length of the longest consecutive elements sequence. C ...

  7. HTML5 manifest离线缓存

    一.基本概念 离线缓存是HTML5新引入的技术,能够让你的Web应用程序指定哪些文件可以缓存在本地,使得你的网络断开时依然可以通过本地的缓存来进行访问浏览. 二.使用方法 1. MIME type 声 ...

  8. #ifdef 的技巧用法

    -- int _tmain(int argc, _TCHAR* argv[]) { #ifdef DEBUG cout<<"DEBUG has been defined" ...

  9. Android app主线程UI更新间歇性崩溃的问题

    对App进行开发测试时,偶尔出现app崩溃的问题.日志如下: 10-25 18:44:52.935 15290-15290/com.zzq.cnblogs E/AndroidRuntime﹕ FATA ...

  10. codeforces 478A.Initial Bet 解题报告

    题目链接:http://codeforces.com/problemset/problem/478/A 题目意思:简单来说,就是初始化的时候,五个人的值都是 b,现在给出每个人最终的状态:就是经过互相 ...