web-dev-qa-db-ja.com

JavaScriptオブジェクトをすばやくクリアする方法は?

JavaScript配列を使用すると、単一の割り当てで空の状態にリセットできます。

array.length = 0;

これにより、配列が空になり、再利用できる状態になります。また、私が理解している限り、単一の「操作」、つまり一定時間です。

JSオブジェクトをクリアする同様の方法はありますか?私はそれらを削除するフィールドを繰り返すことができることを知っています:

for (var prop in obj) { if (obj.hasOwnProperty(prop)) { delete obj[prop]; } }

しかし、これには線形の複雑さがあります。

オブジェクトを捨てて、新しいオブジェクトを作成することもできます。

obj = {};

しかし、新しいオブジェクトの「乱雑な」作成は、IE6のガベージコレクションに問題をもたらします。 ( ここで説明したとおり

152
levik

あなたの質問への短い答えは、私は思う、いいえ(あなたはただ新しいオブジェクトを作成することができます)。

  1. この例では、長さを0に設定しても、ガベージコレクションのすべての要素が残っていると思います。

  2. 頻繁に使用するものであれば、これをObject.prototypeに追加できます。はい、複雑さは直線的ですが、後でガベージコレクションを行わないものはすべて複雑になります。

  3. これが最善の解決策です。あなたの質問とは関係ないことはわかっていますが、IE6のサポートを継続するにはどれくらいの期間が必要ですか?それの使用を中止する多くのキャンペーンがあります。

上記に誤りがある場合は、お気軽に修正してください。

49
jthompson

まあ、物事を簡単にしすぎるリスクがある...

for (var member in myObject) delete myObject[member];

... 1行のコードでオブジェクトを最小限の怖い括弧できれいにするのに非常に効果的だと思われます。すべてのメンバーは、ゴミとして残されるのではなく、本当に削除されます。

明らかにオブジェクト自体を削除したい場合は、そのために別のdelete()を行う必要があります。

102
Wytze

ES5

ES5ソリューションには次のものがあります。

// for enumerable properties
Object.keys(obj).forEach(function (prop) {
  delete obj[prop];
});

// for all properties
Object.getOwnPropertyNames(obj).forEach(function (prop) {
  delete obj[prop];
});

ES6

ES6ソリューションには次のようなものがあります。

// for enumerable properties
for (const prop of Object.keys(obj)) {
  delete obj[prop];
}

// for all properties
for (const prop of Object.getOwnPropertyNames(obj)) {
  delete obj[prop];
}

性能

仕様に関係なく、一般的に最も迅速なソリューションは次のとおりです。

// for enumerable properties
var props = Object.keys(obj);
for (var i = 0; i < props.length; i++) {
  delete obj[props[i]];
}

// for all properties of an object with proto chain
var props = Object.getOwnPropertyNames(obj);
for (var i = 0; i < props.length; i++) {
  delete obj[props[i]];
}

// for all properties of shallow/plain object
for (var key in obj) {
  // this check can be safely omitted in modern JS engines
  // if (obj.hasOwnProperty(key))
    delete obj[key];
}

for..inを浅いオブジェクトまたはプレーンオブジェクトでのみ実行する必要がある理由は、削除可能な独自のプロパティだけでなく、典型的に継承されるプロパティをトラバースするためです。オブジェクトがプレーンであることが確かでない場合は、forObject.getOwnPropertyNamesの方が適しています。

35
Estus Flask

質問を要約すると、IE6 GCのバグによるトラブルを可能な限り回避したいということです。そのバグには2つの原因があります。

  1. ガベージコレクションは、非常に多くの頻度で1回発生しますallocations;したがって、より多くの割り当てを行うと、GCが頻繁に実行されます。
  2. 「空中」にあるオブジェクトが多いほど、各ガベージコレクションの実行にかかる時間が長くなります(ガベージとしてマークされているオブジェクトを確認するためにオブジェクトのリスト全体をクロールするため)。

原因1の解決策は次のようです。割り当ての数を抑えます。新しいオブジェクトと文字列をできるだけ少なく割り当てます。

原因2の解決策は、「ライブ」オブジェクトの数を抑えることです。不要になったらすぐに文字列とオブジェクトを削除し、必要に応じて新しく作成します。

ある程度まで、これらのソリューションは矛盾しています。メモリ内のオブジェクトの数を低く保つには、より多くの割り当てと割り当て解除が必要になります。逆に、同じオブジェクトを絶えず再利用するということは、厳密に必要なオブジェクトよりも多くのオブジェクトをメモリに保持することを意味します。


さて、あなたの質問です。新しいオブジェクトを作成してオブジェクトをリセットするか、すべてのプロパティを削除するかは、後でそれをどうするかによって異なります。

おそらく、新しいプロパティを割り当てる必要があります。

  • すぐに行う場合は、新しいプロパティをすぐに割り当てることをお勧めします。最初に削除またはクリアをスキップします。 (ただし、allプロパティが上書きまたは削除されていることを確認してください!)
  • オブジェクトがすぐに使用されず、後の段階で再配置される場合は、削除するかnullを割り当てて、後で新しいオブジェクトを作成することをお勧めします。

新しいオブジェクトを作成せずに、新しいオブジェクトであるかのようにJScriptオブジェクトをクリアして再利用するための高速で使いやすい方法はありません。 jthompsonが言うように、あなたの質問に対する短い答えは「いいえ」です。

7
Martijn

これを試すことができます。以下の関数は、オブジェクトのプロパティのすべての値を未定義に設定します。ネストされたオブジェクトでも機能します。

var clearObjectValues = (objToClear) => {
    Object.keys(objToClear).forEach((param) => {
        if ( (objToClear[param]).toString() === "[object Object]" ) {
            clearObjectValues(objToClear[param]);
        } else {
            objToClear[param] = undefined;
        }
    })
    return objToClear;
};
6
Alina Poluykova

ES7でObject.observeを楽しみにして、一般的にデータバインディングを使用することを考えると、新しいことです。考慮してください:

var foo={
   name: "hello"
};

Object.observe(foo, function(){alert('modified');}); // bind to foo

foo={}; // You are no longer bound to foo but to an orphaned version of it
foo.name="there"; // This change will be missed by Object.observe()

そのため、この状況では#2が最良の選択となります。

4
Terry Thorsen

小道具は削除できますが、変数は削除しないでください。 delete abc;はES5では無効です(use strictでスローします)。

これをnullに割り当てて、GCに削除するように設定できます(プロパティへの他の参照がある場合は設定しません)

オブジェクトにlengthプロパティを設定しても、何も変わりません。 (プロパティを設定するだけです)

1
Ven