首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

JavaScript 陣列 LINQ 風格查詢擴展:實現 Where、Select、Sum 等鏈式操作

     編輯:關於.NET

前言

C# 的 System.Linq.Enumerable 提供了強大的鏈式查詢語法 (.Where().Select().Sum()),讓集合操作聲明式、可讀性極高。JavaScript 原生陣列雖有 filter/map/reduce,但 API 風格不同。本文展示如何通過擴展 Array.prototype 實現類 LINQ 風格的 Where、Select、Sum、Average 等方法,讓 JS 代碼也能寫出 arr.Where(x => x > 3).Sum() 這樣優雅的邏輯。

核心實現:Where 擴展

Array.prototype.Where = function (func) {
    var copy = [];
    for (var model in this) {
        try {
            if (func(model)) {
                copy.push(model);
            }
        } catch (ex) {
            // 忽略不可枚舉屬性或回調異常
        }
    }
    return copy;
};

使用示例

var array = [1, 2, 3, 4, 5, 6];
var copyArray = array.Where(function (model) {
    return model < 3;
});
console.log(copyArray); // [1, 2]

進階:完整 LINQ 風格擴展庫

(function () {
    // 輔助:轉為真正陣列 (避免 for...in 遍歷原型鏈屬性)
    function toArray(obj) {
        return Array.prototype.slice.call(obj);
    }

    Array.prototype.Where = function (predicate) {
        return toArray(this).filter(predicate);
    };

    Array.prototype.Select = function (selector) {
        return toArray(this).map(selector);
    };

    Array.prototype.Sum = function (selector) {
        var arr = toArray(this);
        if (selector) arr = arr.map(selector);
        return arr.reduce(function (a, b) { return a + b; }, 0);
    };

    Array.prototype.Average = function (selector) {
        var arr = toArray(this);
        if (selector) arr = arr.map(selector);
        return arr.length ? arr.reduce(function (a, b) { return a + b; }, 0) / arr.length : 0;
    };

    Array.prototype.FirstOrDefault = function (predicate) {
        var arr = toArray(this);
        if (predicate) arr = arr.filter(predicate);
        return arr.length ? arr[0] : null;
    };

    Array.prototype.Any = function (predicate) {
        return toArray(this).some(predicate);
    };

    Array.prototype.All = function (predicate) {
        return toArray(this).every(predicate);
    };

    Array.prototype.OrderBy = function (keySelector) {
        return toArray(this).sort(function (a, b) {
            var ka = keySelector(a), kb = keySelector(b);
            return ka > kb ? 1 : ka < kb ? -1 : 0;
        });
    };

    Array.prototype.GroupBy = function (keySelector) {
        var groups = {};
        toArray(this).forEach(function (item) {
            var key = keySelector(item);
            (groups[key] = groups[key] || []).push(item);
        });
        return groups;
    };
})();

鏈式調用示例

var data = [
    {name: 'Alice', age: 25, score: 88},
    {name: 'Bob', age: 30, score: 92},
    {name: 'Charlie', age: 22, score: 75},
    {name: 'David', age: 28, score: 85}
];

// 篩選年齡 > 24,按分數降序,取前兩名姓名
var topTwo = data
    .Where(function (x) { return x.age > 24; })
    .OrderBy(function (x) { return -x.score; }) // 降序技巧
    .Select(function (x) { return x.name; })
    .FirstOrDefault(2); // 假設擴展 FirstOrDefault 支持 count 參數
// 實際需自行實現 Take/Skip

console.log(topTwo); // ['Bob', 'Alice']

注意事項與最佳實踐

  • 不要汙染全域原型:在庫代碼中使用 IIFE 封裝,或僅在應用層引入。大型專案建議使用獨立工具函數 linq(arr).Where(...) 而非擴展原型。
  • 避免 for...in 遍歷陣列:會枚舉原型鏈屬性且順序不保證。務必用 Array.prototype.slice.call(this) 或 [...this] 轉為真陣列再用原生 filter/map/reduce。
  • 效能:原生方法經 JIT 優化,擴展層極薄,效能損耗可忽略。
  • TypeScript 支持:可編寫 interface Array<T> { Where(predicate: (x: T) => boolean): T[]; ... } 獲得型別提示。

總結

通過幾行代碼擴展 Array.prototype,即可在 JavaScript 中享受 LINQ 風格的聲明式集合操作,極大提升代碼可讀性與表達力。生產環境建議採用成熟庫 (如 linq.js, lodash/fp, RxJS) 或自行封裝工具函數,避免原型汙染風險。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved