0

私は、Javascript のプライベート変数、一時変数、および GC に頭を悩ませようとしています。ただし、次の状況で何が起こるかはわかりません。

MyClass = function() {
   this.myProp = new createjs.Shape();

   var tempVar = this.myProp.graphics;
   tempVar.rect(0, 0, 10, 100);
   tempVar = null;

   var isDisposed = false;
   this.dispose = function() {
      if (isDisposed) return;
      isDisposed = true;
   }
}
var anInstance = new myClass();

私の意図は、isDisposedがプライベート ステータス変数を表し、tempVarが use-and-throw 変数になるようにすることでした。

tempVarは GC 用にマークされますか? isDisposedも GC 用にマークされますか? 廃棄用の一時変数を宣言しようとしているとき、およびオブジェクト内にプライベート変数を持とうとしているときに、GC はどのように知るのでしょうか?

Chrome で以下をテストしようとしましたが、myClass のインスタンスが存在する限り、tempVarが GC 処理されないようです。だから今は何を信じていいのかわからない。一時的な使用のために作成したすべてのローカル変数が、オブジェクトの存続期間中スコープ内に存在することを信じられません。

4

1 に答える 1

3

Javascriptには強く型付けされたオブジェクトはありません。nullに設定tempVarすることで、これ以上使用したくないと宣言したり、JavaやC#のようにコレクション用にマークしたりするのではなく、単に(完全に有効な)値を割り当てるだけです。tempVarをオブジェクトの「インスタンス」にしたからといって、変数は実際にはオブジェクトであり、その生涯を通じてそのように扱うことができると考え始めるのは罠です。

基本的に、変数はJavascriptの単なる変数です。それらは何でも含むことができます。その点では、VBやVBScriptに似ています。'a|c'.split('|')スカラーは多くの場合(文字列を文字列にする場合のように)ボクシングを受けますが、ほとんどの場合、それを忘れてください。関数はファーストクラスのオブジェクトです。つまり、変数に割り当てたり、関数から返したり、パラメーターとして渡したりすることができます。

ここで、Javascriptで実際に何かを破棄するには、(オブジェクトの場合のように)そのオブジェクトへのすべての参照を削除するか、オブジェクトのプロパティの場合は次のように削除できます。

delete obj.propertyname;
// or //
delete obj[varContainingPropertyName];

その点を拡張するために、次の2つのコードスニペットは同じ結果を達成します。

function abc() {window.alert('blah');}
var abc = function() {window.alert('blah');}

abcどちらも、たまたま関数であるというローカル変数を作成します。最初のものは、2番目のもののショートカットと考えることができます。

しかし、あなたが私の注意を引いた削除に関するこの優れた記事によると、ローカル変数(実際にはローカル変数でもある関数を含む)を削除することはできません。例外があります(変数がを使用して作成された場合eval、または変数がグローバルスコープにあり、IE <= 8を使用していない場合、またはIE <= 8を使用していて、変数がx = 1技術的には暗黙的にグローバルスコープで作成された場合巨大なバグ)なので、詳細については記事を読んdeleteでください。

あなたに役立つかもしれないもう一つの重要なことは、Javascriptでは関数だけがスコープを持っていることを知っていることです(そしてwindowブラウザの実装や他の実装のグローバルスコープは何でも)。非関数オブジェクトと囲まれたコードブロックにはスコープがありません(そして、のプロトタイプはであるため、関数もオブジェクトですが、特別なものであるため{ }、このように言います)。これは、たとえば、次のコードを検討することを意味します。FunctionObject

function doSomething(x) {
   if (x > 0) {
      var y = 1;
   }
   return y;
 }

変数yのスコープはブロックではなく関数1であるため、で実行するとこれが返されます。したがって、実際には、宣言をブロックに配置することは誤りであり、誤解を招く可能性があります。これは、宣言が実際には(おそらく実際にはそうではありませんが)関数スコープに引き上げられているためです。x > 0var

javascriptのクロージャを読む必要があります(そのリンクの品質を保証することはできません)。そうすることはおそらく助けになるでしょう。変数の関数スコープがどこかで維持されるときはいつでも、すべての関数のプライベート変数も維持されます。あなたができる最善のことは、それらを設定することですundefined(これは、Javascriptでは「null」よりも「何も」ありません)。これは、それらが持つオブジェクト参照を解放しますが、変数を実際に割り当て解除してGCで使用できるようにすることはありません。

一般的なGCingの落とし穴については、関数にDOM要素に対するクロージャーがあり、どこかでDOM要素もその関数を参照している場合、ページがアンロードされるか循環参照を壊すまで、どちらもGCされないことに注意してください。IEの一部のバージョン、またはすべてのバージョンでは、このような循環参照によってメモリリークが発生し、ブラウザを閉じるまでGCが実行されません。

質問に直接答えるには:

  • tempVarこれはローカル変数であり、Javascriptのローカル変数は削除できないため、その一部である関数がすべての参照を解放するまで、GCのマークは付けられません。
  • isDisposedと同じ性質を持っていtempVarます。
  • Javascriptには、「廃棄を目的とした一時変数」の区別はありません。ECMAScriptの新しいバージョンでは、関数のパブリック(またはプライベート?)プロパティを定義するために、実際のゲッターとセッターを使用できます。
  • Firefoxでの削除に関する記事で説明されているように、ブラウザのコンソールは誤解を招く結果を提供する可能性があります。
  • 信じられないかもしれませんが、Javascriptでは、変数がクロージャ内に存在する限り、その変数はインスタンス化されたままです。これは通常は問題ではなく、ガベージコレクションされていない小さな変数が原因でブラウザが本当にメモリ不足になることはありません。変数をundefined使い終わったらに設定して、安心してください。問題が発生することはないと思います。懸念がある場合は、ローカルオブジェクトvar tmpObj = {tempVar: 'something'};を宣言し、それが完了したら、を発行できますdelete tmpObj.tempVar;。しかし、私の意見では、これは不必要にあなたのコードを乱雑にするでしょう。

基本的に、私の提案は、他のプログラミング言語から来ることで、プログラミング言語がどのようにあるべきかについて先入観を持っていることを理解することです働くために。それらの概念のいくつかは、理想的なプログラミング言語の観点から妥当性があるかもしれません。ただし、これらの概念を放棄し、少なくとも今のところ、Javascriptが実際にどのように機能するかを受け入れるのがおそらく最善です。自分の前に行った人(私など)のアドバイスに自信を持って違反するのに十分な経験を積むまでは、深刻な欠陥を修正する可能性よりも、Javascriptコードに有害なアンチパターンを導入するリスクが高くなります。言語で。Dispose()を使用する必要がないことは、本当に良いニュースかもしれません。Javascriptが単純に必要としない、この厄介な広範なタスクなので、機能の記述により多くの時間を費やし、変数の有効期間の管理に費やす時間を減らすことができます。勝つ!

私の言葉を、その意味どおりに親切に受け止めていただければ幸いです。私は決して自分自身をJavascriptの専門家だとは考えていません。それは、Javascriptの使用方法と落とし穴を理解する上で、ある程度の経験と確かな能力を持っているということだけです。

聞いてくれてありがとう!

于 2012-11-30T06:34:42.947 に答える