10

このずさんなモードの関数があったと仮定すると、(何らかの奇妙な理由で) そのargumentsオブジェクトが呼び出し元に返されます。

function example(a, b/* ...*/) {
    var c = // some processing
    return arguments;
}

呼び出し ( ) の結果を格納すると、( 、などを含むvar d=example();) の変数環境がガベージ コレクションされるのを防ぐことができますか? Arguments オブジェクトの内部セッターとゲッターは、クロージャーから返された関数と同じように、引き続きそれを参照する可能性があります。デモ:exampleabc

function example(a, b) {
  var c = Array(1000).fill(0); // some large object
  return {
    args: arguments,
    set: function(x) { a = x; },
    get: function() { return a; }
  };
}
var d = example('init');
console.log(d.get());
d.args[0] = 'arguments update'; // assigns the `a` variable
console.log(d.get());
d.set('variable update');
console.log(d.args); // reads the `a` variable

ユースケースがほとんどないことは知っていますが (Arguments オブジェクトを渡すことは、おそらく配列との類似性のため、悪い習慣と見なされます) が、これはより理論的な問題です。さまざまな EcmaScript 実装はこれをどのように処理しますか? 仕様に近い実装ですか?

通常の閉鎖のようcにガベージコレクションされ、リークされないことを期待しますが、どうですか? オブジェクトのプロパティを取得するとどうなりますか?bdeletearguments

4

2 に答える 2

4

このことを考慮:

var x = function() {
  return arguments;
}
console.log( x() === x() );

これは、同じargumentsオブジェクトではないため、誤りです。これは、(の呼び出しごとにx)新しく構築されたオブジェクトであり、すべてのパラメータのが格納されています。それでも、次のプロパティがありますarguments

var y = x([]);
console.log(y instanceof Object); // true
console.log(y instanceof Array);  // false
console.log(y.length); // 1
console.log(y.callee + '');       // function() { return arguments; }

しかし、これにはまだまだあります。arguments明らかに、パラメータとして関数に送信されたオブジェクトは、返された場合、GCによって収集されません。

var z = x({some: 'value'});
console.log(z[0]); // {some:'value'}

これは予想されることです。結局のところ、関数内でローカルオブジェクトを宣言し、関数の最初のパラメーターの値をオブジェクト「0」プロパティとして割り当ててから、このオブジェクトを返すことで、同様の結果を得ることができます。どちらの場合も、参照されるオブジェクトはまだ「使用中」なので、大したことはないと思います。

しかし、これはどうですか?

var globalArgs;
var returnArguments = function() {
  var localArgs = arguments;
  console.log('Local arguments: ');
  console.log(localArgs.callee.arguments); 
  if (globalArgs) { // not the first run
    console.log('Global arguments inside function: ');   
    console.log(globalArgs.callee.arguments); 
  }
  return arguments;
}
globalArgs = returnArguments('foo');
console.log('Global arguments outside function #1: ');   
console.log(globalArgs.callee.arguments);
globalArgs = returnArguments('bar');
console.log('Global arguments outside function #2: ');   
console.log(globalArgs.callee.arguments);

出力:

Local arguments: ["foo"]
Global arguments outside function #1: null
Local arguments: ["bar"]
Global arguments inside function: ["bar"]
Global arguments outside function #2: null

ご覧のとおり、オブジェクトを返しarguments、それを変数に割り当てると、関数内でそのプロパティはそれ自体callee.argumentと同じデータセットを指します。argumentsこれもまた予想されます。しかし、関数の外側はnullvariable.callee.argumentsに等しい(未定義ではない)。

于 2012-11-22T15:53:32.660 に答える
0

特定の JavaScript エンジンについて調査を行わなければ、これについて最終的に回答することは困難です。arguments Objectただし、とによって作成されたコンテキストとの関係exampleは、他のローカル変数とそのホスト コンテキストの関係と同じであると主張します。

つまり、値を保存しても、そのコンテキストも保存する必要はありません。

1 つの注意点は、指定された がバインドされarguments.calleeているコンテキスト (つまりFunction)への参照であるプロパティです。arguments Objectただし、このプロパティは厳密モードには存在せず、非推奨でもあります

それ以外は、を返して保存してarguments Objectもメモリリークは発生しないと想定しても安全だと思います。

于 2012-11-22T19:36:06.163 に答える