8

メモリ リークを防ぐために使用される null への代入の修正の性質に関して、誰かが私のためにかゆみを掻くことができますか?

メモリ リークを防ぐために、DOM オブジェクトと JS オブジェクト間の循環参照を停止する次の手法はよく知られています。

    function foo() {
      var ele = document.getElementById("someParagraphId");

      ele.onclick = function() {
        //some action here
      };

      ele = null;
    }

問題は、なぜ上記が機能するのかということです。「ele」を null に設定すると、循環参照は確実に停止しますが、「ele」への将来の参照も防止されませんか?

    function foo() {
      var ele = document.getElementById("someParagraphId");

          ele.onclick = function() {
              console.log("accessing ele ... after set to null " + ele.onclick);
          };

      ele = null;

    }

それでも、イベントリスナーが起動します。「ele」オブジェクトがnullであると不平を言うでしょう(これは私たちが期待することです)。

上記の動作を考えると、Javascript エンジンの実装がイベント リスナーへの何らかの内部参照を保持し、イベントがトリガーされたときに呼び出されるのはこの参照であると推測するのは正しいでしょうか?

eventHandlerRef = //assignment to "ele.onclick" handler/listener;

上記のような参照があった場合、null への代入の修正は実装依存ではないでしょうか。それとも、ECMAScript 仕様の一部ですか。

私の理解では、この修正は常にクロス ブラウザーに対して安全です。null 割り当てを適用する前に、ブラウザーの種類を検出/スニッフィングすることについて具体的に言及している例はあまり見当たりません。

===============編集==================

質問の仕方が原因で、私が伝えようとしていたことから、無意識のうちに直接的な議論をしてしまう可能性があると思います。参照されているいくつかの概念:

オブジェクト ハンドル/オブジェクト参照 ala:

 var obj1, obj2;
     obj1 = {foo: "bar"}; //obj1 points to the an area of the heap allocated 
                          //for the object literal.

 obj2 = obj1;     //obj2 points to the same position in the heap
                      //as obj1.

 //obj1 = null or
 obj1 = {/*another obj literal*/}  //the new object literal is created 
                                       //and allocated in some other part 
                                       //in the heap, and obj1 now points 
                                       //to the new location.

//obj2 is unaffected by obj1's re-assignment. 

上記は私のかゆみがある場所ではなく、次の行を追加したことを後悔しています。

console.log("accessing ele ... after set to null " + ele.onclick);

上記は、これを閉鎖の質問に見せます。元の投稿に示されているように、エラーがスローされることを完全に期待していました。

私のかゆみは...のコンテキストに沿ったものですが、何らかの理由で、ele.onlick()イベントが発生したときにJavascriptエンジンが直接呼び出し、要素をnullに設定することは、次のフローに似ていると考え続けています:

var obj = {};
obj.method = function() {};

obj = null;
//error calling obj.method(), i.e., obj is null

元の投稿で、ele が null に設定された後もイベント ハンドラーが起動することがわかっていることを考えると、私の考えでは、フローは次のようになります。

var obj = {};
obj.method = function() {};

var objRef = obj; 

obj = null;  

//The Javascript Engine calling objRef.method when event triggered.

私のかゆみは、上記のほとんどの Javascript 実装がどのように機能するか、割り当てられたイベントハンドラーを指している内部参照であり、イベントがトリガーされたときに呼び出されるのはこの内部参照ですか?

または別の言い方をすれば、JavaScript エンジンの実装が を直接呼び出す ele.onclick()を妨げているのは何ですか (設計とアーキテクチャの問題はさておき)。

多分私の思考プロセスは異なって動作しますが、最初にnullへの代入の修正に遭遇したとき、要素参照がnullであり、ハンドラーのコードがまだ実行?

4

3 に答える 3

7

古い回答をすべて破棄し、編集に対処します:)

もっと簡単な例を見てみましょう: textContent.

var ele = document.getElementById('foo');
ele.textContent = 'abc';
ele = null;

このコードは、 を に設定しtextContent#fooabcの参照を破棄しますele。また頼んだらどうなるの#foo...

var ele = document.getElementById('foo');
ele.textContent = 'abc';
ele = null;
ele = document.getElementById('foo');
console.log('#foo is ' + ele.textContent);

ログに記録されます"#foo is abc"。これは#foo、 が私のスクリプトの外部に存在し、documentそれへの参照を保持していることを示しているだけです ( のメソッドを呼び出して戻ってきたためdocument)。イベント ハンドラーと同じように機能します。

var ele = document.getElementById('foo');
ele.onclick = function() { console.log('abc'); };
ele = null;
ele = document.getElementById('foo');
console.log('#foo.onclick is ' + ele.onclick);

イベント ハンドラーは特別な種類のプロパティではありません。それらは、(関数への) 参照を書き込む単なる変数です。これらは大まかに関数型言語機能であり、関数は単純な値として使用できます。JavaScript 実装は、参照からではなく、DOM 参照からイベント ハンドラーを呼び出すだけeleです。を使わずに、別の簡単な例を作りましょうdocument.getElementById

var a = {};
var b = a;
b.foo = function() { console.log("hello world!"); };
console.log(a.foo + " is the same as " + b.foo);
b = null;
console.log("Even though b is " + b + ", a.foo is still " + a.foo);
a.foo();

ご覧のように、関数は割り当て先の参照に関連付けられていません。参照が指すオブジェクトに関連付けられています。関数の割り当てに使用したものからだけでなく、オブジェクトへの任意の参照からそれらを呼び出すことができます。

そのため、オブジェクトの正しい動作に影響を与えることなく、参照を無効にして循環依存を解消できます。

于 2011-06-13T04:58:42.127 に答える
1

私は JavaScript の達人ではありません。しかし、変数オブジェクトの違いを思い出させるだけで、少なくとも部分的にあなたの質問に答えることができると思います。コードを 1 行ずつ見ていきましょう。

var ele = document.getElementById("someParagraphId");

ここでは、次の 2 つのことを行っています。

  • 変数の宣言( ele)
  • DOM 要素 ( object ) への参照をその変数に割り当てる

次:

ele.onclick = function() {
    console.log("accessing ele ... after set to null " + ele.onclick);
};

ここでは、変数を使用して、参照する オブジェクト(再び DOM 要素)のイベントにeleコールバックを割り当てています。onclick

ついに:

ele = null;

最後に、変数へのnull参照を割り当てます。ele直前に行ったオブジェクトを参照しなくなります。ただし、そのオブジェクトは同じonclickハンドラーでまだそこにあります。それは変わっていません。

ハンドラーがまだ呼び出されるという事実は、正しい動作です。エラーについては、その DOM 要素のonclickイベントに割り当てられた関数をもう一度見てみましょう。

console.log("accessing ele ... after set to null " + ele.onclick);

これeleは、先ほど割り当てた変数nullとまったく同じです。したがって、この関数が呼び出されると、オブジェクトonclickに関連付けられたハンドラーが消えていないため、null 参照例外がスローされます。

于 2011-06-13T05:05:38.180 に答える
0

eleを呼び出すことで最初に取得するためdocument.getElementById("someParagraphId")、参照するオブジェクトは を割り当てる前に既にメモリ内に存在しますele。これはドキュメントの一部です。もちろん、メモリ内には 以外の参照がありますele

于 2011-06-13T04:58:20.627 に答える