0

何度も再作成されるクラスを作っているので、メモリを節約するために完全に削除する必要があります。基本的に、可能であれば、その包含変数にアクセスする必要があります。

次に例を示します。

function example(){
  this.id=0;
  this.action=function(){alert('tost');}
  this.close=function(){ delete this;}
}

var foo=new example();

私の質問は:

サンプル関数内からfoo変数にアクセスして、削除するにはどうすればよいですか?

4

3 に答える 3

1

window.fooそのグローバル変数にアクセスします。

this.close=function(){ delete window.foo; }

ただし、グローバル変数、delete、windowには厄介なものがあることを覚えているので、それ以外の方法で、window.foo = null;たとえば単に使用することをお勧めします。

別の関数で定義された変数にアクセスする場合は、このSOの質問に対する回答を読む必要があります。

必要なのはガベージコレクタがそのオブジェクトを解放できるようにすることなので、オブジェクトへの参照が残っていないことを確認する必要があります。オブジェクトを操作するコードは、グローバル変数とローカル変数、および属性を介してオブジェクトを複数回参照できるため、これは非常に難しい(つまり不可能な)場合があります。

オブジェクトにアクセスするためのプロキシを作成することで、オブジェクトへの直接参照を防ぐことができます。残念ながら、javascriptは動的ゲッターとセッター(キャッチオールとも呼ばれます)を十分にサポートしていません(ただし、一部のブラウザーでは、このSOの質問を参照してください) 、したがって、すべてのフィールドとメソッド(とにかく単なるフィールド)アクセスを基になるオブジェクトに簡単にリダイレクトすることはできません。特に、基になるオブジェクトに多くのフィールドが追加され、動的に削除される場合(つまりthis.anewfield = anewvalue)。

これがsmipleプロキシ(jsfiddle.netのコード)です:

function heavyobject(destroyself, param1, param2) {
    this.id=0;
    this.action=function(){alert('tost ' + param1 + "," + param2);};
    this.close=function(){ destroyself(); }
}

function proxy(param1, param2) {
    object = null;
    // overwrites object, the only reference to
    // the heavyobject, with a null value.
    destroyer = function() { object = null; };
    object = new heavyobject(destroyer, param1, param2);
    return function(fieldname, setvalue) {
        if (object != null) {
            if (arguments.length == 1)
                return object[fieldname];
            else
                object[fieldname] = setvalue;
        }
    };
}
var foo = proxy('a', 'b');
alert(foo("action")); // get field action
foo("afield", "avalue"); // set field afield to value avalue.
foo("action")(); // call field action
foo("close")(); // call field close
alert(foo("action")); // get field action (should be 'undefined').

これは、単一の引数で呼び出されたときにラップされたオブジェクトのフィールドを取得し、2つの引数で呼び出されたときにフィールドを設定する関数を返すことによって機能します。これは、heavyobjectへの唯一の参照が関数内のobjectローカル変数であることを確認することによってproxy機能します。

ヘビーオブジェクトのコードは決してリークしてはなりませんthis(決して返さない、参照を保持する関数を返さないvar that = this、別の変数のフィールドに格納しない)。そうしないと、ヘビーオブジェクトを指す外部参照が作成され、削除できなくなる可能性があります。

ヘビーオブジェクトのコンストラクターがコンストラクターdestroyself()内から(またはコンストラクターによって呼び出される関数から)呼び出す場合、効果はありません。

別のより単純なプロキシ。フィールドを追加したり、フィールドを読み取ったり、メソッドを呼び出したりできる空のオブジェクトを提供します。これでは、外部参照を逃れることはできないと確信しています。

コード(jsfiddle.netにもあります):

function uniquelyReferencedObject() {
    object = {};
    f = function(field, value) {
        if (object != null) {
            if (arguments.length == 0)
                object = null;
            else if (arguments.length == 1)
                return object[field];
            else
                object[field] = value;
        }
    };
    f.destroy = function() { f(); }
    f.getField = function(field) { return f(field); }
    f.setField = function(field, value) { f(field, value); }
    return f;
}
// Using function calls
o = uniquelyReferencedObject();
o("afield", "avalue");
alert(o("afield")); // "avalue"
o(); // destroy
alert(o("afield")); // undefined
// Using destroy, getField, setField
other = uniquelyReferencedObject();
other.setField("afield", "avalue");
alert(other.getField("afield")); // "avalue"
other.destroy();
alert(other.getField("afield")); // undefined
于 2012-08-08T13:09:28.243 に答える
1

真実は、Javascriptではオブジェクトを削除できないということです。

次に、削除演算子を使用すると、一部のオブジェクトのプロパティのみが受け入れられます。そのため、delete を使用するときは、一般に のようなものを渡す必要がありますobj.p。次に、変数名だけを渡します。実際には、これは「グローバル オブジェクトのプロパティ」を意味し、 とdelete p同じdelete window.pです。内部で何が起こるかはわかりませんdelete thisが、結果としてブラウザはそれをスキップします。

さて、実際に何を削除しdeleteますか? オブジェクトへの参照を削除します。これは、オブジェクト自体がまだメモリ内にあることを意味します。これを排除するには、具象オブジェクトへのすべての参照を削除する必要があります。どこでも - 他のオブジェクトから、クロージャーから、イベント ハンドラーから、リンクされたデータから、それらすべてから。ただし、オブジェクト自体には、このすべての参照に関する情報がないため、オブジェクト自体からオブジェクトを削除する方法はありません。このコードを見てください:

var obj = <our object>;
var someAnother = {
       ...
       myObjRef: obj
       ...
 }
var someAnotherAnother = {
       ...
       secondRef : obj
       ...
}

someAnother.myObjRef obj をメモリから削除するには、 and を 削除する必要がありsomeAnoterAnother.secondRefます。それらすべてを知っているプログラムの部分からのみ行うことができます。

そして、そこにいくつもの参照がある場合、どのようにして何かを削除するのでしょうか? この問題を解決するには、いくつかの方法があります。

  • このオブジェクトが参照されるように、そこからプログラム内で 1 つのポイントだけを作成します。実際、プログラムには参照が 1 つしかありません。そしてそれを削除します - オブジェクトはガベージコレクターによって殺されます。これは、上記の「プロキシ」の方法です。これには欠点があります (言語自体からのサポートがまだないため、cool と niceobj.x=1をに変更する必要がobj.val('x',1)あります。また、これはそれほど明白ではありません。実際には、obj へのすべての参照をプロキシへの参照に変更します。代わりに、プロキシは常にメモリに残ります。オブジェクトのサイズ、オブジェクトの数、および実装に応じて、これにより利益が得られるかどうかが決まります. または、事態を悪化させることさえあります. たとえば、オブジェクトのサイズがプロキシ自体のサイズに近い場合、価値はありません.

  • オブジェクトを使用するすべての場所に、このオブジェクトへの参照を削除するコードを追加します。ある場所でa を呼び出すと、obj.close()削除する必要があるものがすべてわかっているため、より明確で簡単に使用できます。obj.close()それへの参照を殺す代わりに。一般に、この参照を別のものに変更します。

      var x = new obj; //now our object is created and referenced
      x = null;// now our object **obj** still im memory 
      //but doest have a references to it 
      //and after some milliseconds obj is killed by GC...
    
      //also you can do delete for properties
      delete x.y; //where x an object and x.y = obj
    

    ただし、このアプローチでは、参照が非常に理解しにくい場所にある可能性があることを覚えておく必要があります。例えば:

      function func() {
         var x= new obj;// our heavy object
         ...
         return function result() {
             ...some cool stuff..
         }
      }
    

    参照は関数のクロージャーに格納されresult、obj は、何かへの参照がある間はメモリに残りますresult

  • それ自体が重いオブジェクトを想像するのは困難です。最も現実的なシナリオは、内部にデータが含まれている場合です。この場合、このデータをクリーンアップするクリーンアップ関数をオブジェクトに追加できます。オブジェクトのプロパティとして巨大なバッファ (たとえば、数値の配列) があり、メモリを解放したい場合は、このバッファをクリアして、メモリ内に数十バイトのオブジェクトがまだ残っているとします。また、インスタンスを小さく保つために、関数をプロトタイプにすることを忘れないでください。

于 2012-08-10T12:02:30.943 に答える
0

JavaScriptの削除演算子に関する非常に詳細な情報へのリンクを次に示します。

http://perfectionkills.com/understanding-delete/

于 2012-08-08T13:13:11.890 に答える