Array/Stringの汎用メソッドをこだわって定義する

FirefoxではArray.prototypeやString.prototypeにあるメソッドを簡単に転用できるように、コンストラクタ(Array, String)自身に汎用メソッド(generic method)が定義されています。
これにより、

  • Array.prototype.forEach.call(nodeList, body.appendChild, body)
    Array.forEach(nodeList, body.appendChild, body) と書くことができる
  • Array.prototype.slice.call(arguments, 1)
    Array.slice(arguments, 1) と書くことができる

ところが、これはECMAScript標準ではないので、Firefox以外では定義されていません。Array | MDNに次のようなshimが用意されています。

/*globals define*/
// Assumes Array extras already present (one may use shims for these as well)
(function () {
    'use strict';
 
    var i,
        // We could also build the array of methods with the following, but the
        //   getOwnPropertyNames() method is non-shimable:
        // Object.getOwnPropertyNames(Array).filter(function (methodName) {return typeof Array[methodName] === 'function'});
        methods = [
            'join', 'reverse', 'sort', 'push', 'pop', 'shift', 'unshift',
            'splice', 'concat', 'slice', 'indexOf', 'lastIndexOf',
            'forEach', 'map', 'reduce', 'reduceRight', 'filter',
            'some', 'every', 'isArray'
        ],
        methodCount = methods.length,
        assignArrayGeneric = function (methodName) {
            var method = Array.prototype[methodName];
            Array[methodName] = function (arg1) {
                return method.apply(arg1, Array.prototype.slice.call(arguments, 1));
            };
        };
 
    for (i = 0; i < methodCount; i++) {
        assignArrayGeneric(methods[i]);
    }
}());

isArrayは消さなければなりません。ミスだと思います。使う分にはこれで十分ですが、次の点が気になります。

  • 定義される関数は無名関数(nameなし)なので、デバッグ時のコールスタックが嫌な感じになる
  • 定義される関数のlengthプロパティが0なので、lengthプロパティを使う何か(例えばカリー化)に使えない

そこで、evalなりFunctionコンストラクタなりを使って、関数名と引数を合わせるように定義することを考えます。

var call = Function.prototype.call;

function assignArrayGeneric(methodName) {
    var method = Array.prototype[methodName];
    var args = generateArgsString(method.length + 1);
    Array[methodName] = new Function('call', 'method',
        'return function ' + methodName + '(' + args +
        ') { return call.apply(method, arguments); };'
        )(call, method);
}

function generateArgsString(length) {
    var args = [];
    var i;
    for (i = 0; i < length; ++i) {
        args[i] = '$' + i;
    }
    return args.join(', ');
}

引数の数は、this相当の引数を受け取る分、+ 1 しています(Firefoxに合わせています)。これで、例えば Array.forEach には function forEach($0, $1) { return call.apply(method, arguments); } が定義されます(いわゆるクロージャにより、callFunction.prototype.callmethodArray.prototype.forEachを指します)。関数名もlengthプロパティも、外部から使う分には十分になりました。
でも、欲が出てきて、今度は引数名が機械的$0, $1 である点が気になりました。動的解析に対応したIDEで、$0, $1 よりは array, callbackfn と表示された方が嬉しいです。
Functionコンストラクタを使うのもどうかと思うので、ES5の仕様書を見ながらそれぞれ書きました。

ご自由にお使いください。