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:"Pearson"},
{FirstName:"Kate",LastName:"Johnson"},
{FirstName:"Josh",LastName:"Sutherland"},
{FirstName:"John",LastName:"Ronald"},
{FirstName:"Steve",LastName:"Pinkerton"}
];
var exampleArray = JSLINQ(myList)
.Where(function(item){ return item.FirstName == "Chris"; })
.OrderBy(function(item) { return item.FirstName; })
.Select(function(item){ return item.FirstName; });
Linq to JavaScript整體架構
(function() {
JSLINQ = window.JSLINQ = function(dataItems) {
return new JSLINQ.fn.init(dataItems);
};
JSLINQ.fn = JSLINQ.prototype = {
init: function(dataItems) {
this.items = dataItems;
},
Where: function(clause) {
...
},
...
}
JSLINQ.fn.init.prototype = JSLINQ.fn;
})();
這個結構的關鍵點有
- 最外層用一個匿名函數(function(){}))()構造塊級作用域
- 不采用new JSLINQ().Where()方式,而是將JSLINQ()作為一個工廠方法,返回init()函數的實例對象
- 為了在init()函數的實例對象上繼續調用JSLINQ原型對象的方法,將JSLINQ.fn.init.prototype指向JSLINQ.fn,也即JSLINQ.prototype
- 通過這一操作,調用new JSLINQ().Where()時,首先可以在init()函數的實例對象中查詢,未找到后在init.prototype中查詢,未找到,繼續沿原型鏈向上查找,在JSLINQ.prototype上找到Where方法
- 如果沒有這一操作,調用new JSLINQ().Where()時,將會提示Where方法未被定義
觀察Linq to JavaScript整體結構會發現,其結構與JQuery的非常相似
(function( window, undefined ) {
var jQuery = (function() {
// 構建jQuery對象
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context, rootjQuery );
}
// jQuery對象原型
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ) {
}
};
// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;
// 到這里,jQuery對象構造完成,后邊的代碼都是對jQuery或jQuery對象的擴展
return jQuery;
})();
window.jQuery = window.$ = jQuery;
})(window);
LINQ to JavaScript詳細分析
//構造塊級作用域
(function() {
//工廠方法,返回init()的實例對象
JSLINQ = window.JSLINQ = function(dataItems) {
return new JSLINQ.fn.init(dataItems);
};
JSLINQ.fn = JSLINQ.prototype = {
init: function(dataItems) {
this.items = dataItems;
}
//clause是一個函數表達式
Where: function(clause) {
var item;
//創建本地數組,存儲返回值
var newArray = new Array();
// The clause was passed in as a Method that return a Boolean
for (var index = 0; index < this.items.length; index++) {
//將元素傳入函數
if (clause(this.items[index], index)) {
newArray[newArray.length] = this.items[index];
}
}
//將結果數組傳入JSLINQ(),創建新的init()對象實例,以便可以鏈式調用
return new JSLINQ(newArray);
},
Select: function(clause) {
var item;
var newArray = new Array();
// The clause was passed in as a Method that returns a Value
for (var i = 0; i < this.items.length; i++) {
if (clause(this.items[i])) {
newArray[newArray.length] = clause(this.items[i]);
}
}
return new JSLINQ(newArray);
}
...
JSLINQ.fn.init.prototype = JSLINQ.fn;
}
})();
更多
從LINQ to JavaScript使用示例中可以看到,Where(),Select()等方法中僅支持匿名函數的方式
而在.net3.0之后,LINQ的Where等擴展方法中,已經可以使用便捷的lambda表達式
如果你希望在javascript中也使用lambda表達式語法書寫linq,可以關注LINQ for JavaScript,這是另一個提供linq支持的javascript庫,項目地址http://linqjs.codeplex.com/
LINQ for JavaScript調用示例
var jsonArray = [
{ "user": { "id": 100, "screen_name": "d_linq" }, "text": "to objects" },
{ "user": { "id": 130, "screen_name": "c_bill" }, "text": "g" },
{ "user": { "id": 155, "screen_name": "b_mskk" }, "text": "kabushiki kaisha" },
{ "user": { "id": 301, "screen_name": "a_xbox" }, "text": "halo reach" }
]
// ["b_mskk:kabushiki kaisha", "c_bill:g", "d_linq:to objects"]
var queryResult = Enumerable.From(jsonArray)
.Where(function (x) { return x.user.id < 200 })
.OrderBy(function (x) { return x.user.screen_name })
.Select(function (x) { return x.user.screen_name + ':' + x.text })
.ToArray();
// shortcut! string lambda selector
var queryResult2 = Enumerable.From(jsonArray)
.Where("$.user.id < 200")
.OrderBy("$.user.screen_name")
.Select("$.user.screen_name + ':' + $.text")
.ToArray();
標簽:
javascript,
源碼分析

