6

次のコードがあるとしましょう

/*...*/
var _fun = fun;
fun = function() {
  /*...*/
  _fun.apply(this, arguments);
}

傍受ロジックでラップしようとしたため、.lengthデータを失いました。_fun

以下は動作しません

var f = function(a,b) { };
console.log(f.length); // 2
f.length = 4;
console.log(f.length); // 2

注釈付きのES5.1 仕様.lengthは、次のように定義されています。

Object.defineProperty(fun, "length", {
  value: /*...*/,
  writable: false,
  configurable: false,
  enumerable: false
}

内部のロジックが正確であるfun必要がある場合、データ.lengthを破壊せずにこの関数を傍受して上書きするにはどうすればよいでしょうか?.length

私は使用する必要があると感じており、同じ数の引数で新しい文字列を作成するevalのは危険です。Function.prototype.toStringこれは避けたい。

4

4 に答える 4

3

他の方法を好むのはわかっていますが、私が考えられるのは、Functionコンストラクターで何かをハックすることだけです。控えめに言っても面倒ですが、うまくいくようです:

var replaceFn = (function(){
    var args = 'abcdefghijklmnopqrstuvwxyz'.split('');
    return function replaceFn(oldFn, newFn) {
        var argSig = args.slice(0, oldFn.length).join(',');
        return Function(
            'argSig, newFn',
            'return function('
                + argSig +
            '){return newFn.apply(this, arguments)}'
        )(argSig, newFn);
    };
}());

// Usage:
var _fun = fun;

fun = replaceFn(fun, function() {
  /* ... */
  _fun.apply(this, arguments);
});
于 2011-09-06T21:22:26.003 に答える
2

この目的のために次の関数を使用します。妥当なパラメーター数を持つ関数では非常に高速であり、受け入れられている回答よりも柔軟で、26 個を超えるパラメーターを持つ関数で機能します。

function fakeFunctionLength(fn, length) {
    var fns = [
        function () { return fn.apply(this, arguments); },
        function (a) { return fn.apply(this, arguments); },
        function (a, b) { return fn.apply(this, arguments); },
        function (a, b, c) { return fn.apply(this, arguments); },
        function (a, b, c, d) { return fn.apply(this, arguments); },
        function (a, b, c, d, e) { return fn.apply(this, arguments); },
        function (a, b, c, d, e, f) { return fn.apply(this, arguments); }
    ], argstring;

    if (length < fns.length) {
        return fns[length];
    }

    argstring = '';
    while (--length) {
        argstring += ',_' + length;
    }
    return new Function('fn',
        'return function (_' + argstring + ') {' +
            'return fn.apply(this, arguments);' +
        '};')(fn);
}
于 2011-11-19T08:49:40.573 に答える
2

長さを正しく一貫して偽造することは、javascript の最終的なフロンティアであり、それがほとんどの始まりと終わりです。ほぼすべてを偽造できる言語では、長さはまだ魔法のようなものです。ES6 は配信されますが、使用しているエンジンとバージョンに応じて、多かれ少なかれそれを偽造することができます。一般的な Web 互換性については、それは道のりです。Proxies/noSuchMethod はしばらくの間 Mozilla にありました。Proxies と WeakMaps は、V8 で Chromium とノード (有効にするにはフラグが必要) で使用できるようになり、長さを正しく偽造するために必要なツールを提供します。

「長さ」の詳細: http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/

最終的な解決策: http://wiki.ecmascript.org/doku.php?id=harmony:proxies + http://wiki.ecmascript.org/doku.php?id=harmony:weak_maps

于 2011-09-07T06:06:49.227 に答える
0

任意の数のパラメーターを持つ関数をサポートする必要がある場合にのみ、eval/Functionルートをたどる必要があります。妥当な上限を設定できる場合(私の例は5)、次のように実行できます。

var wrapFunction = function( func, code, where ){
  var f;
  switch ( where ) {
    case 'after':
      f = function(t,a,r){ r = func.apply(t,a); code.apply(t,a); return r; }
    break;
    case 'around':
      f = function(t,a){ return code.call(t,func,a); }
    break;
    default:
    case 'before':
      f = function(t,a){ code.apply(t,a); return func.apply(t,a); }
    break;
  }
  switch ( func.length ) {
    case 0: return function(){return f(this, arguments);}; break;
    case 1: return function(a){return f(this, arguments);}; break;
    case 2: return function(a,b){return f(this, arguments);}; break;
    case 3: return function(a,b,c){return f(this, arguments);}; break;
    case 4: return function(a,b,c,d){return f(this, arguments);}; break;
    case 5: return function(a,b,c,d,e){return f(this, arguments);}; break;
    default:
      console.warn('Too many arguments to wrap successfully.');
    break;
  }
}

whereコードをラップするこの方法は、さまざまなスイッチを作成することによっても拡張できます。私が実装beforeafterたのは、それらが自分のプロジェクトに最も役立つからです。そしてaround、それがLispを思い出させるからです。この設定を使用すると、ラッピング(var f)を外部コードに渡すこともできます。これにより、キーワードのシステムのようなプラグインを開発できます。whereつまり、wrapFunctionサポートされているものを簡単に拡張またはオーバーライドできます。

もちろん、コードの実際のラップ方法は好きなように変更できます。重要なのは、文字列の作成やへの受け渡しを気にせずに、999やAdrianLangと同様の手法を使用することnew Functionです。

于 2013-02-15T12:30:16.110 に答える