LINQ to Javascript源码分析

  1 //-----------------------------------------------------------------------
  2 // Part of the LINQ to JavaScript (JSLINQ) v2.20 Project - http://jslinq.codeplex.com
  3 // Copyright (C) 2012 Chris Pietschmann (http://pietschsoft.com). All rights reserved.
  4 // This license can be found here: http://jslinq.codeplex.com/license
  5 //-----------------------------------------------------------------------
  6 (function () {
  7     var JSLINQ = window.jslinq = window.JSLINQ = function (dataItems) {
  8         return new JSLINQ.fn.init(dataItems);
  9     },
 10     utils = {
 11         processLambda: function (clause) {
 12             // This piece of "handling" C#-style Lambda expression was borrowed from:
 13             // linq.js - LINQ for JavaScript Library - http://lingjs.codeplex.com
 14             // THANK!!
 15             if (utils.isLambda(clause)) {
 16                 var expr = clause.match(/^[(\s]*([^()]*?)[)\s]*=>(.*)/);
 17                 return new Function(expr[1], "return (" + expr[2] + ")");
 18             }
 19             return clause;
 20         },
 21         isLambda: function (clause) {
 22             return (clause.indexOf("=>") > -1);
 23         },
 24         randomIndex: function (max, existing) {
 25             var q, r, f = function () { return this == r; };
 26             if (!existing) {
 27                 return parseInt(Math.random() * max, 10);
 28             } else {
 29                 q = JSLINQ(existing);
 30                 r = -1;
 31                 while (r < 0 || q.Where(f).Count() !== 0) {
 32                     r = utils.randomIndex(max);
 33                 }
 34                 return r;
 35             }
 36         }
 37     };
 38     JSLINQ.fn = JSLINQ.prototype = {
 39         init: function (dataItems) {
 40             this.items = dataItems;
 41         },
 42
 43         // The current version of JSLINQ being used
 44         jslinq: "2.20",
 45
 46         toArray: function () { return this.items; },
 47         where: function (clause) {
 48             var newArray = [], len = this.items.length;
 49
 50             // The clause was passed in as a Method that return a Boolean
 51             for (var i = 0; i < len; i++) {
 52                 if (clause.apply(this.items[i], [this.items[i], i])) {
 53                     newArray[newArray.length] = this.items[i];
 54                 }
 55             }
 56             return JSLINQ(newArray);
 57         },
 58         select: function (clause) {
 59             var item, newArray = [], field = clause;
 60             if (typeof (clause) !== "function") {
 61                 if (clause.indexOf(",") === -1) {
 62                     clause = function () { return this[field]; };
 63                 } else {
 64                     clause = function () {
 65                         var i, fields = field.split(","), obj = {};
 66                         for (i = 0; i < fields.length; i++) {
 67                             obj[fields[i]] = this[fields[i]];
 68                         }
 69                         return obj;
 70                     };
 71                 }
 72             }
 73
 74             // The clause was passed in as a Method that returns a Value
 75             for (var i = 0; i < this.items.length; i++) {
 76                 item = clause.apply(this.items[i], [this.items[i]]);
 77                 if (item) {
 78                     newArray[newArray.length] = item;
 79                 }
 80             }
 81             return JSLINQ(newArray);
 82         },
 83         orderBy: function (clause) {
 84             var tempArray = [];
 85             for (var i = 0; i < this.items.length; i++) {
 86                 tempArray[tempArray.length] = this.items[i];
 87             }
 88
 89             if (typeof (clause) !== "function") {
 90                 var field = clause;
 91                 if (utils.isLambda(field)) {
 92                     clause = utils.processLambda(field);
 93                 }
 94                 else {
 95                     clause = function () { return this[field]; };
 96                 }
 97             }
 98
 99             return JSLINQ(
100             tempArray.sort(function (a, b) {
101                 var x = clause.apply(a, [a]), y = clause.apply(b, [b]);
102                 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
103             })
104         );
105         },
106         orderByDescending: function (clause) {
107             var tempArray = [], field;
108             for (var i = 0; i < this.items.length; i++) {
109                 tempArray[tempArray.length] = this.items[i];
110             }
111
112             if (typeof (clause) !== "function") {
113                 field = clause;
114                 if (utils.isLambda(field)) {
115                     clause = utils.processLambda(field);
116                 }
117                 else {
118                     clause = function () { return this[field]; };
119                 }
120             }
121
122             return JSLINQ(tempArray.sort(function (a, b) {
123                 var x = clause.apply(b, [b]), y = clause.apply(a, [a]);
124                 return ((x < y) ? -1 : ((x > y) ? 1 : 0));
125             }));
126         },
127         selectMany: function (clause) {
128             var r = [];
129             for (var i = 0; i < this.items.length; i++) {
130                 r = r.concat(clause.apply(this.items[i], [this.items[i]]));
131             }
132             return JSLINQ(r);
133         },
134         count: function (clause) {
135             if (clause === undefined) {
136                 return this.items.length;
137             } else {
138                 return this.Where(clause).items.length;
139             }
140         },
141         distinct: function (clause) {
142             var item, dict = {}, retVal = [];
143             for (var i = 0; i < this.items.length; i++) {
144                 item = clause.apply(this.items[i], [this.items[i]]);
145                 // TODO - This doesn‘t correctly compare Objects. Need to fix this
146                 if (dict[item] === undefined) {
147                     dict[item] = true;
148                     retVal.push(item);
149                 }
150             }
151             dict = null;
152             return JSLINQ(retVal);
153         },
154         any: function (clause) {
155             for (var i = 0; i < this.items.length; i++) {
156                 if (clause.apply(this.items[i], [this.items[i], i])) { return true; }
157             }
158             return false;
159         },
160         all: function (clause) {
161             for (var i = 0; i < this.items.length; i++) {
162                 if (!clause(this.items[i], i)) { return false; }
163             }
164             return true;
165         },
166         reverse: function () {
167             var retVal = [];
168             for (var i = this.items.length - 1; i > -1; i--) {
169                 retVal[retVal.length] = this.items[i];
170             }
171             return JSLINQ(retVal);
172         },
173         first: function (clause) {
174             if (clause !== undefined) {
175                 return this.Where(clause).First();
176             }
177             else {
178                 // If no clause was specified, then return the First element in the Array
179                 if (this.items.length > 0) {
180                     return this.items[0];
181                 } else {
182                     return null;
183                 }
184             }
185         },
186         last: function (clause) {
187             if (clause !== undefined) {
188                 return this.Where(clause).Last();
189             }
190             else {
191                 // If no clause was specified, then return the First element in the Array
192                 if (this.items.length > 0) {
193                     return this.items[this.items.length - 1];
194                 } else {
195                     return null;
196                 }
197             }
198         },
199         elementAt: function (i) {
200             return this.items[i];
201         },
202         concat: function (array) {
203             var arr = array.items || array;
204             return JSLINQ(this.items.concat(arr));
205         },
206         intersect: function (secondArray, clause) {
207             var clauseMethod, sa = (secondArray.items || secondArray), result = [];
208             if (clause !== undefined) {
209                 clauseMethod = clause;
210             } else {
211                 clauseMethod = function (item, index, item2, index2) { return item === item2; };
212             }
213
214             for (var a = 0; a < this.items.length; a++) {
215                 for (var b = 0; b < sa.length; b++) {
216                     if (clauseMethod(this.items[a], a, sa[b], b)) {
217                         result[result.length] = this.items[a];
218                     }
219                 }
220             }
221             return JSLINQ(result);
222         },
223         defaultIfEmpty: function (defaultValue) {
224             if (this.items.length === 0) {
225                 return defaultValue;
226             }
227             return this;
228         },
229         elementAtOrDefault: function (i, defaultValue) {
230             if (i >= 0 && i < this.items.length) {
231                 return this.items[i];
232             }
233             return defaultValue;
234         },
235         firstOrDefault: function (defaultValue) {
236             return this.First() || defaultValue;
237         },
238         lastOrDefault: function (defaultValue) {
239             return this.Last() || defaultValue;
240         },
241         take: function (count) {
242             return this.Where(function (item, index) { return index < count; });
243         },
244         skip: function (count) {
245             return this.Where(function (item, index) { return index >= count; });
246         },
247         each: function (clause) {
248             var len = this.items.length;
249             for (var i = 0; i < len; i++) {
250                 clause.apply(this.items[i], [this.items[i], i]);
251             }
252             return this;
253         },
254         random: function (count) {
255             var len = this.Count(), rnd = [];
256             if (!count) { count = 1; }
257             for (var i = 0; i < count; i++) {
258                 rnd.push(utils.randomIndex(len - 1, rnd));
259             }
260             rnd = JSLINQ(rnd);
261             return this.Where(function (item, index) {
262                 return rnd.Where(function () {
263                     return this == index;
264                 }).Count() > 0;
265             });
266         }
267     };
268
269     (function (fn) {
270         fn.ToArray = fn.toArray;
271         fn.Where = fn.where;
272         fn.Select = fn.select;
273         fn.OrderBy = fn.orderBy;
274         fn.OrderByDescending = fn.orderByDescending;
275         fn.SelectMany = fn.selectMany;
276         fn.Count = fn.count;
277         fn.Distinct = fn.distinct;
278         fn.Any = fn.any;
279         fn.All = fn.all;
280         fn.Reverse = fn.reverse;
281         fn.First = fn.first;
282         fn.Last = fn.last;
283         fn.ElementAt = fn.elementAt;
284         fn.Concat = fn.concat;
285         fn.Intersect = fn.intersect;
286         fn.DefaultIfEmpty = fn.defaultIfEmpty;
287         fn.ElementAtOrDefault = fn.elementAtOrDefault;
288         fn.FirstOrDefault = fn.firstOrDefault;
289         fn.LastOrDefault = fn.lastOrDefault;
290         fn.Take = fn.take;
291         fn.Skip = fn.skip;
292         fn.Each = fn.each;
293         fn.Random = fn.random;
294     })(JSLINQ.fn);
295
296     JSLINQ.fn.init.prototype = JSLINQ.fn;
297 })();

具体分析下次有时间再写!

时间: 2024-11-06 13:46:32

LINQ to Javascript源码分析的相关文章

LINQ to JavaScript 源码分析

在.net平台工作一年有余,最喜欢的应属Linq特性 在几个移动端web小项目过程中,前端需要对json对象集合进行比较复杂的操作,为提高开发效率,引入了LINQ to Javascript,该项目地址:http://jslinq.codeplex.com/ LINQ to JavaScript代码不到两百行,可读性很好,今天来对它的源代码进行下分析 Linq to JavaScript使用示例 var myList = [ {FirstName:"Chris",LastName:&q

Linq扩展最后遗留之SelectMany,Zip,SequenceEqual源码分析

Linq扩展最后遗留之SelectMany,Zip,SequenceEqual源码分析 一: AsParallel [并行化查询] 这个函数的功效就是将计算结果多线程化.[并行计算] =>[多核] 二:AsQueryable [将lambda表达式作为数据结构存储起来,Expresstion 表达式树] 三:Join 多表关联操作,我们可以用"查询关键字"解决. 为了更加的脱俗易懂,我们建议用人性化的"查询关键字"来解决这个复杂的Join,lambda. 四:

Linq特取操作之ElementAt,Single,Last,First源码分析

Linq特取操作之ElementAt,Single,Last,First源码分析 一:linq的特取操作 First/FirstOrDefault, Last/LastOrDefault, ElementAt/ElementAtOrDefault, Single/SingleOrDefault 二:First/FirstOrDefault 介绍 解释: 用于返回序列中的第一个值 异常: 如果当前集合没有值的话,如果你取第一个值,会抛出throw Error.NoElements();异常. pu

Linq分区操作之Skip,SkipWhile,Take,TakeWhile源码分析

Linq分区操作之Skip,SkipWhile,Take,TakeWhile源码分析 二:linq的分区操作 常用的分区操作:Take,TakeWhile,Skip,SkipWhile 三:Take 1. 注释: 从序列的开头返回指定数量的连续元素 2. 实战: var nums = new int[] { 10, 20, 30, 40, 50, 60 }; var query = nums.Take(2).ToList(); // 10,20 3. 探究源码: 四:TakeWhile 1. 注

ABP源码分析三十三:ABP.Web

ABP.Web模块并不复杂,主要完成ABP系统的初始化和一些基础功能的实现. AbpWebApplication : 继承自ASP.Net的HttpApplication类,主要完成下面三件事一,在Application_Start完成AbpBootstrapper的初始化.整个ABP系统的初始化就是通过AbpBootstrapper完成初始化的.二,在Application_BeginRequest设置根据request或cookie中的Culture信息,完成当前工作线程的CurrentCu

Cordova Android源码分析系列一(项目总览和CordovaActivity分析)

PhoneGap/Cordova是一个专业的移动应用开发框架,是一个全面的WEB APP开发的框架,提供了以WEB形式来访问终端设备的API的功能.这对于采用WEB APP进行开发者来说是个福音,这可以避免了原生开发的某些功能.Cordova 只是个原生外壳,app的内核是一个完整的webapp,需要调用的原生功能将以原生插件的形式实现,以暴露js接口的方式调用. Cordova Android项目是Cordova Android原生部分的Java代码实现,提供了Android原生代码和上层We

Jquery源码分析

1.概述 jQuery是一个非常优秀的Js库,与prototype,YUI,Mootools等众多的Js类库相比,它剑走偏锋,从web开发最实用的角度出发,抛除了一些中看但不实用的东西,为开发者提供一个短小精悍的类库.由于其个短小精悍,使用简单方便,性能相对高效.众多的开发者都选择Jquery来进行辅助的web开发. 在使用jquery时开发,我们也会时常碰到许多的问题,但是jquery的代码很晦涩,难起看懂,当开发时出现了问题,看不懂源码,不知道如何去排错. John Resig,Jquery

java使用websocket,并且获取HttpSession,源码分析

一:本文使用范围 此文不仅仅局限于spring boot,普通的spring工程,甚至是servlet工程,都是一样的,只不过配置一些监听器的方法不同而已. 本文经过作者实践,确认完美运行. 二:Spring boot使用websocket 2.1:依赖包 websocket本身是servlet容器所提供的服务,所以需要在web容器中运行,像我们所使用的tomcat,当然,spring boot中已经内嵌了tomcat. websocket遵循了javaee规范,所以需要引入javaee的包 <

jquery源码分析(二)——结构

再来复习下整体架构: jQuery源码分析(基于 jQuery 1.11 版本,共计8829行源码) (21,94)                定义了一些变量和函数jQuery=function(){} (96,280)        给jQuery添加一些方法和属性,jQuery.fn=jQuery.prototype(285,347)        extend:        jQuery的一些继承方法        更容易进行后续的扩展