Array.prototype.map の自前実装

javascript array map 自前 という検索ワードでのリファラがあったので map の自前実装でも書いてみます。
とはいえ、すでにやってる方がいらっしゃるので

毛色を変えて畳み込み関数による map の実装でも紹介してみます。

まぁ関数型言語に慣れている方には何の面白みもないかもしれませんが^^;;; JavaScript高階関数に触れたって人には畳み込み関数の強力さを知ってもらえるのではないかと。

という訳で畳み込み関数です。prototype.js だと inject、関数型言語だと foldl、JavaScript1.8 だと reduce と様々な名前で呼ばれてますが、ここでは JavaScript1.8 に従って reduce にしておきます。

if (!Array.prototype.reduce) {
    Array.prototype.reduce = function(callback, init, thisObject) {
        if (this.length == 0) return init;
        var index = init !== undefined ? 0 : 1;
        var result = init !== undefined ? init : this[0];
        for (var n = this.length; index < n; index++) {
            result = callback.call(thisObject, result, this[index], index, this);
        }
        return result;
    }
}

各要素を左から畳み込んでいくメソッドですね。こんな使い方をします。

[1, 2, 3, 4, 5].reduce(function(a, b) {return a + b;}); // 1 + 2 + 3 + 4 + 5 で 15 になります。

この reduce を使って map を定義すると以下の様になります。

if (!Array.prototype.map) {
    Array.prototype.map = function(callback, thisObject) {
        return this.reduce(function(result, e, index, array) {
            result[result.length] = callback.call(thisObject, e, index, array);
            return result;
        }, []);
    }
}

ポイントは畳み込む結果のオブジェクトは配列でも構わないって所ですね。
この柔軟さが畳み込み関数を非常に強力な点です。

余談ですが、PHP の array_reduce という関数は初期値に数値しか与えられないので非常に使い道が限定された関数になっています。現場で使って気付いた時に思わず殺意を覚えました(笑) (参考: PHP の array_reduce - Rainy Day Codings)

因みに filter も reduce を使って定義することができます。強力ですね reduce。

if (!Array.prototype.filter) {
    Array.prototype.filter = function(callback, thisObject) {
        return this.reduce(function(result, e, index, array) {
            if (callback.call(thisObject, e, index, array)) {
                result[result.length] = e;
            }
            return result;
        }, []);
    }
}