Подтвердить что ты не робот

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"}}

Почему это?

Плюс, у меня есть еще один вопрос. В чем смысл добавлять объекты непосредственно к WeakSets, например:

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

Являются ли эти трассирующие сбои или я что-то упускаю?

И, наконец, что такое практическое использование WeakSet, если мы не можем даже перебирать его или не получать текущий размер?

4b9b3361

Ответ 1

он не удаляется из WeakSet. Почему это?

Скорее всего, потому, что сборщик мусора еще не запущен. Тем не менее, вы говорите, что используете Traceur, поэтому просто может быть, что они не поддерживаются должным образом. Интересно, как console может показать содержимое WeakSet в любом случае.

В чем смысл непосредственного добавления объектов в WeakSets?

Абсолютно нет смысла добавлять объектные литералы к WeakSet s.

Каково практическое использование WeakSet, если мы не можем даже перебирать его и не получать текущий размер?

Все, что вы можете получить, это один бит информации: Является ли объект (или вообще, значение), содержащимся в наборе?

Это может быть полезно в ситуациях, когда вы хотите "пометить" объекты без фактического их изменения (установив на них свойство). Множество алгоритмов содержит какое-то "если бы было уже замечено x" (может быть хорошим примером может быть обнаружение цикла JSON.stringify), а когда вы работаете с предоставленными пользователем значениями, используйте Set/WeakSet было бы целесообразно. Преимущество WeakSet заключается в том, что его содержимое может быть собрано в мусор, пока ваш алгоритм все еще работает, поэтому он помогает сократить потребление памяти (или даже предотвращает утечки), когда вы имеете дело с большим количеством данных, которые лениво (возможно даже асинхронно).

Ответ 2

Это очень трудный вопрос. Чтобы быть абсолютно честным, я понятия не имел в контексте JavaScript поэтому я спросил в esdiscuss и получил убедительный ответ от Domenic.

WeakSets полезны для обеспечения безопасности и проверки. Если вы хотите изолировать фрагмент JavaScript. Они позволяют использовать тег объекта, чтобы указать, что он принадлежит к определенному набору объектов.

Скажем, у меня есть класс 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 - я хочу, чтобы вы сделали ApiRequest с объектами, которые я вам даю поэтому вы не можете обойти любые ограничения, которые у меня есть.

Однако на данный момент ничто не мешает вам:

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.getOwnPropertyNames или Object.getOwnSymbols. Итак, вы подходите ко мне и делаете:

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.

Итак, коротко - WeakMaps полезны для написания платформ в JavaScirpt. Обычно такая проверка выполняется на стороне С++, но добавление этих функций позволит перемещать и создавать вещи в JavaScript.

(Конечно, все a WeakSet может также делать WeakMap, который отображает значения в true, но это верно для любой конструкции map/set)

(Как говорит Берги, никогда не бывает причин добавлять объектный литерал непосредственно к WeakMap или WeakSet)

Ответ 3

По определению WeakSet имеет только три ключевые функции

  • Слабо связать объект с набором
  • Удалить ссылку на объект из набора
  • Убедитесь, что объект уже связан с установленным

Звучит более симпатично?

В некоторых приложениях разработчикам, возможно, потребуется реализовать быстрый способ итерации с помощью серии данных, которая загрязнена множествами и множеством избыточности, но вы хотите выбрать только те, которые ранее не были обработаны (уникальны). 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();
}

Одна из лучших структур данных для приложения выше - Bloom filter, что очень хорошо подходит для массового размера данных. Однако для этой цели вы также можете использовать WeakSet.

Ответ 4

WeakSet - это упрощение 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.
};