3

さまざまな目的で、関数をオブジェクトにラップする必要があることがよくあります。lengthラッパー関数で元の関数のプロパティを保持するエレガントな方法はありますか?

例えば:

var x = {
    a: function(arg1, arg2) { /* do something */ }
};

function wrap(obj) {
    var original = obj.a;
    obj.a = function wrapper() {
        console.log('a called');
        original.apply(this, arguments);
    };
}

x.a.length; // => 2
wrap(x);
x.a.length; // => 0

私がしたいこと:

var x = {
    a: function(arg1, arg2) { /* do something */ }
};

function wrap(obj) {
    var original = obj.a;
    obj.a = function wrapper() {
        console.log('a called');
        original.apply(this, arguments);
    };
    obj.a.length = original.length;
}

x.a.length; // => 2
wrap(x);
x.a.length; // => 2 (actual still 0)

ただし、書き込み可能ではないため、これは機能しませんlength

現時点で思いつく唯一の解決策は、(1) 関数を文字列として動的に生成するか、evalまたはnew Function(2) 異なる長さのプロキシ関数の巨大な配列を持ち、正しい長さに対応するプロキシ関数を選択することです. これは私には洗練された解決策とは思えません。また、関数内の各引数を指定length せずに任意の関数を作成できるようにすることは、合理的な要求のようです。

bindこれを内部的に行うことができるようです:

function a(b, c) { }
a.bind(null).length; // => 2

これにより、元の長さのラッパー関数が作成されます! それはまさに私が自分でできるようになりたいことです。

他に方法はありますか?

4

2 に答える 2

1

シンプルな eval(...) アプローチが好きです。

function wrap(obj) {
    var f = obj.fun.toString();
    f = f.replace("{", "{ alert('wrapper'); ");
    obj.fun = eval('['+f+']')[0];
}

これを拡張して、ラッパー関数を表す wrap の 2 番目のパラメーターを持ち、それらを結合するための文字列操作をさらに洗練させることができます。

ラッピングの透過性が目標である場合は、プログラミング言語の動的機能を利用してください。


JavaScript ファイルに対して追加の処理を行う場合は、ホット パッチ/ラッピングを組み込むことができます。

var x = {
    a: function(arg1, arg2) {
        (x._a || (function(){}))();
        ... do actual function stuff ...
    }
}
function wrap(obj) {
    obj._a = function() {
        console.log("ok");
    }
}
于 2012-10-24T15:58:45.890 に答える
0

ラップされた関数とラップされていない関数の長さを同じ方法で取得する必要があるが、 length プロパティを使用せずに処理できる場合は、次のようなものが役立ちます。

Function.prototype.mylengthf = function() {
    return this.mylength | this.length;
};

var x = {
    a: function(arg1, arg2) { /* do something */ },
    b: function(arg1, arg2, arg3) { /* do something else */ }
};

function wrap(obj) {
    var original = obj.a;
    obj.a = function wrapper() {
        console.log('a called');
        original.apply(this, arguments);
    };
    obj.a.mylength = original.length;
}

log(x.a.length); // => 2
wrap(x);
log(x.a.length); // => 0
log(x.a.mylengthf()); // => 2
log(x.b.mylengthf()); // => 3
​
于 2012-10-24T15:13:03.993 に答える