web-dev-qa-db-ja.com

ECMAScript 6:WeakSetとは何ですか?

WeakSetは、弱参照によって要素を格納することになっています。つまり、オブジェクトが他から参照されていない場合は、WeakSetから削除する必要があります。

次のテストを作成しました。

var weakset = new WeakSet(),
    numbers = [1, 2, 3];

weakset.add(numbers);
weakset.add({name: "Charlie"});

console.log(weakset);

numbers = undefined;

console.log(weakset);

私の[1, 2, 3]配列は何からも参照されず、WeakSetから削除されません。コンソールは以下を印刷します。

WeakSet {[1, 2, 3], Object {name: "Charlie"}}
WeakSet {[1, 2, 3], Object {name: "Charlie"}}

何故ですか?

さらに、もう1つ質問があります。次のように、オブジェクトをWeakSetsに直接追加することのポイントは何ですか?

weakset.add({name: "Charlie"});

これらのTraceurの不具合はありますか、それとも何か不足していますか?

そして最後に、WeakSetを反復処理することも現在のサイズを取得することさえできない場合、WeakSetの実用的な用途は何ですか?

49
Robo Robok

weakSetから削除されていません。何故ですか?

おそらく、ガベージコレクターがまだ実行されていないためです。ただし、Traceurを使用していると言われているので、適切にサポートされていない可能性があります。とにかくconsoleWeakSetの内容をどのように表示できるのだろうか。

WeakSetsにオブジェクトを直接追加する意味は何ですか?

WeakSetsにオブジェクトリテラルを追加する意味はまったくありません。

WeakSetを反復処理したり、現在のサイズを取得したりすることさえできない場合、WeakSetの実際の使用法は何ですか?

取得できるのは1ビットの情報だけです。オブジェクト(または一般に値)はセットに含まれていますか?

これは、実際にオブジェクトを変更せずにオブジェクトに「タグ付け」したい場合に役立ちます(オブジェクトにプロパティを設定します)。多くのアルゴリズムには、ある種の「if xが既に見られた」という条件(a JSON.stringifyサイクル検出は良い例かもしれませんが、ユーザー提供の値を使用する場合は、Set/WeakSetを使用することをお勧めします。ここでのWeakSetの利点は、アルゴリズムの実行中にその内容をガベージコレクションできることです。そのため、大量のデータを処理しているときのメモリ消費量を削減(またはリークを防止)するのに役立ちます。遅延的に(おそらく非同期的に)生成されます。

49
Bergi

これは本当に難しい質問です。完全に正直に言うと、私はJavaScriptのコンテキストで何も考えていませんでした だからesdiscussで尋ねましたDomenic から納得のいく答えを得ました。

WeakSetは、securityおよびvalidationの理由で役立ちます。 JavaScriptの一部を分離できるようにする場合。オブジェクトをtagして、オブジェクトの特別なセットに属していることを示すことができます。

クラスApiRequestがあるとします:

class ApiRequest {
  constructor() {
    // bring object to a consistent state, use platform code you have no cirect access to
  }

  makeRequest() {
    // do work 
  }
}

今、私はJavaScriptプラットフォームを書いています-私のプラットフォームではJavaScriptを実行して呼び出しを行うことができます-必要な呼び出しを行うにはApiRequest-私はあなたが与えたオブジェクトでApiRequestsだけを作りたいですそのため、私が設定した制約をバイパスすることはできません。

ただし、現時点では、次のことを妨げるものはありません。

ApiRequest.prototype.makeRequest.call(null, args); // make request as function
Object.create(ApiRequest.prototype).makeRequest(); // no initialization
function Foo(){}; Foo.prototype = ApiRequest.prototype; new Foo().makeRequest(); // no super

など、通常のリストまたはApiRequestオブジェクトの配列を保持することはできないことに注意してください。これにより、ガベージコレクションができなくなります。クロージャ以外に、Object.getOwnPropertyNamesObject.getOwnSymbolsなどのパブリックメソッドを使用して何でも実現できます。だからあなたは私を1つ上にして、次のことをします:

const requests = new WeakSet();
class ApiRequest {
  constructor() {
    requests.add(this);
  }

  makeRequest() {
    if(!request.has(this)) throw new Error("Invalid access");
    // do work
  }
}

さて、私が何をしても、有効なApiRequestオブジェクトを保持して、そのmakeRequestメソッドを呼び出す必要があります。これは、WeakMap/WeakSetなしでは不可能です。

つまり、要するに-WeakMapは、JavaScirptでプラットフォームを作成するのに役立ちます。通常、この種の検証はC++側で行われますが、これらの機能を追加すると、JavaScriptでの移動や作成が可能になります。

(もちろん、WeakSetWeakMapに値をマップするtrueを実行することもすべて実行できますが、それはすべてのマップ/セット構成に当てはまります)

(ベルギの答えのように、オブジェクトリテラルをWeakMapまたはWeakSetに直接追加する理由はありません。)

26

定義により、WeakSetには3つの主要な機能しかありません

  • オブジェクトをセットに弱くリンクします
  • セットからオブジェクトへのリンクを削除する
  • オブジェクトが既にセットにリンクされているかどうかを確認します

もっとよく聞こえますか?

一部のアプリケーションでは、開発者は多くの冗長性で汚染された一連のデータを反復処理するための迅速な方法を実装する必要がありますが、前に処理されていないもののみを選択する必要があります(一意)。 WeakSetが役立ちます。以下の例を参照してください。

var processedBag = new WeakSet();
var nextObject = getNext();
while (nextObject !== null){
    // Check if already processed this similar object?
    if (!processedBag.has(nextObject)){
        // If not, process it and memorize 
        process(nextObject);
        processedBag.add(nextObject);
    }
    nextObject = getNext();
}

上記のアプリケーションに最適なデータ構造の1つはブルームフィルターで、これは大量のデータサイズに非常に適しています。ただし、この目的にもWeakSetの使用を適用できます。

11
TaoPR

「弱い」セットまたはマップは、物の任意のコレクションを保持する必要があるが、メモリが不足した場合にそれらの物がガベージコレクションされるのをコレクション内に存在させたくない場合に役立ちます。 (ガベージコレクションdoesが発生すると、「リープされた」オブジェクトはコレクションから静かに消えるので、実際にそれらがなくなったかどうかを確認できます。)

これらは、たとえば、ルックアサイドキャッシュとして使用する場合に優れています。"最近このレコードを取得しましたか?"何かを取得するたびに、マップに入れて、 JavaScriptガベージコレクターは「リストのトリミング」を担当し、一般的なメモリ条件(合理的に予測できない)に応じて自動的にトリミングします。

唯一の欠点は、これらのタイプが「列挙可能」ではないことです。エントリのリストを反復処理することはできません。おそらく、これによりそれらのエントリが「タッチ」され、目的が達成されない可能性が高いためです。しかし、それはわずかな代償です(そして、必要に応じて、「could、必要に応じてそれをコード化する」)。

2
Mike Robinson

ガベージコレクションがまだ行われていないため、コンソールにコンテンツが誤って表示されている可能性があります。したがって、オブジェクトはガベージコレクトされていないため、オブジェクトはまだウィークセットのままです。

弱点セットに特定のオブジェクトへの参照がまだあるかどうかを確認したい場合は、WeakSet.prototype.has()メソッドを使用します。このメソッドは、名前が示すとおり、オブジェクトがウィークセットにまだ存在するかどうかを示すbooleanを返します。

例:

var weakset = new WeakSet(),
    numbers = [1, 2, 3];

weakset.add(numbers);
weakset.add({name: "Charlie"});

console.log(weakset.has(numbers));

numbers = undefined;

console.log(weakset.has(numbers));
1

WeakSetは、値が常にブール値trueになるWeakMapの簡略化です。 JavaScriptオブジェクトにタグを付けて、一度だけ何かを実行したり、特定のプロセスに関する状態を維持したりできます。理論的には、値を保持する必要がないため、使用するメモリが少し少なく、WeakMapよりもわずかに高速に動作するはずです。

var [touch, untouch] = (() => {
    var seen = new WeakSet();
    return [
        value => seen.has(value)) || (seen.add(value), !1),
        value => !seen.has(value) || (seen.delete(value), !1)
    ];
})();

function convert(object) {
    if(touch(object)) return;
    extend(object, yunoprototype); // Made up.
};

function unconvert(object) {
    if(untouch(object)) return;
    del_props(object, Object.keys(yunoprototype)); // Never do this IRL.
};
1
jgmjgm