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

JavaScript 讓正則表達式像函數一樣可呼叫:call/apply 擴充與陣列方法 Polyfill

     編輯:PHP 綜合知識

背景

ECMAScript 4 曾提議讓正則表達式具備 call()/apply() 方法,後來雖未納入標準,但我們可自行擴充 RegExp.prototype 實現類似功能。這不僅便於函數式寫法,也能讓正則在 Array.prototype.filter/map/every/some 等高階函數中直接使用,實現「鴨子類型」多型。

核心擴充碼

// 讓 RegExp 可像函數一樣被呼叫
RegExp.prototype.call = function (context, str) {
    return this.exec(str);
};
RegExp.prototype.apply = function (context, args) {
    return this.exec(args[0]);
};

// 兩方法皆忽略 context 參數,傳 null 即可

配合陣列高階函數使用

// 篩選以 "a" 開頭的字串
const result = ["a", "b", "ab", "ba"].filter(/^a/);
// result === ["a", "ab"]

因 exec() 回傳陣列或 null,在布林語境下自動轉為 true/false,完美符合 filter 回調函數簽名。

陣列方法 Polyfill(支援舊瀏覽器)

if (!Array.prototype.filter) {
    Array.prototype.filter = function (func, context) {
        const results = [];
        for (let i = 0; i < this.length; i++) {
            if (i in this && func.call(context, this[i], i, this)) {
                results.push(this[i]);
            }
        }
        return results;
    };
}

if (!Array.prototype.every) {
    Array.prototype.every = function (func, context) {
        for (let i = 0; i < this.length; i++) {
            if (i in this && !func.call(context, this[i], i, this)) return false;
        }
        return true;
    };
}

if (!Array.prototype.some) {
    Array.prototype.some = function (func, context) {
        for (let i = 0; i < this.length; i++) {
            if (i in this && func.call(context, this[i], i, this)) return true;
        }
        return false;
    };
}

if (!Array.prototype.map) {
    Array.prototype.map = function (func, context) {
        const results = [];
        for (let i = 0; i < this.length; i++) {
            if (i in this) results[i] = func.call(context, this[i], i, this);
        }
        return results;
    };
}

為何需要 RegExp.prototype.call?

Firefox 早期已實作 Array.prototype.filter,且 exec 間接呼叫可行。但在未實作 call 的瀏覽器(如舊版 IE),filter 內部會嘗試呼叫傳入函數的 call 方法,導致正則表達式報錯。補上 RegExp.prototype.call 即可跨瀏覽器正常運作。

實用範例

// 從字串陣列提取符合 Email 格式的項目
const emails = ["test@example.com", "invalid", "foo@bar.org", "no-at-sign"];
const valid = emails.filter(/^[^\s@]+@[^\s@]+\.[^\s@]+$/);
// valid === ["test@example.com", "foo@bar.org"]

// map 搭配正則提取分組
const urls = ["https://a.com", "https://b.org", "ftp://c.net"];
const domains = urls.map(/https?:\/\/([^\/]+)/); 
// domains === ["a.com", "b.org", null] (第三項不匹配回傳 null)

結語

透過幾行原型擴充,正則表達式即化身為可攜帶的謂詞函數,極大提升函數式程式碼的表達力。配合陣列方法 Polyfill,即可在不支援 ES5 的舊環境中優雅地使用現代陣列操作。

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