1

たとえば、呼び出された関数とその引数を出力するジェネリック関数ラッパーを作成したいと思います。

これは、arguments準配列と単純な呼び出しによって簡単に実行できます。例えば:

function wrap(target, method) {
    return function() {
        console.log(Array.prototype.slice.call(arguments).join(', '));
        return method.apply(target, arguments);
    }
}

ただし、この方法ではもちろん、呼び出された関数のアリティが完全に失われます(知らなかった場合は、JavaScript関数のアリティ(引数の数)をそのlengthプロパティから取得できます)。

ラップされた関数の引数をそれ自体にコピーするラッパー関数を動的に作成する方法はありますか?


新しいFunctionオブジェクトを作成することを考えましたが、argumentsプロパティが非推奨になっているため、引数リストを静的に抽出する方法がわかりません。

4

1 に答える 1

2

を使用したソリューションは次のFunctionとおりです。

// could also generate arg0, arg1, arg2, ... or use the same name for each arg
var argNames = 'abcdefghijklmnopqrstuvwxyz';
var makeArgs = function(n) { return [].slice.call(argNames, 0, n).join(','); };

function wrap(target, method) {
    // We can't have a closure, so we shove all our data in one object
    var data = {
        method: method,
        target: target
    }

    // Build our function with the generated arg list, using `this.`
    // to access "closures"
    f = new Function(makeArgs(method.length),
        "console.log(Array.prototype.slice.call(arguments).join(', '));" +
        "return this.method.apply(this.target, arguments);"
    );
    // and bind `this` to refer to `data` within the function
    return f.bind(data);
}

編集:

閉鎖の問題を修正する、より抽象的な解決策を次に示します。

function giveArity(f, n) {
    return new Function(makeArgs(n),
        "return this.apply(null, arguments);"
    ).bind(f);
}

そして、呼び出されたときにコンテキストを保持するより良いもの:

function giveArity(f, n) {
    return eval('(function('+makeArgs(n)+') { return f.apply(this, arguments); })')
}

使用されます:

function wrap(target, method) {
    return giveArity(function() {
        console.log(Array.prototype.slice.call(arguments).join(', '));
        return method.apply(target, arguments);
    }, method.length)
}
于 2012-11-07T14:27:56.537 に答える