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, если мы не можем ни перебрать его, ни получить текущий размер?

8 ответов

Решение

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

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

Какой смысл добавлять объекты в WeakSets напрямую?

Нет абсолютно никакого смысла добавлять объектные литералы в WeakSets.

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

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

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

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

Слабые наборы полезны в целях безопасности и проверки. Если вы хотите иметь возможность выделить фрагмент 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. Обычно такого рода проверка выполняется на стороне C++, но добавление этих функций позволит перемещать и создавать объекты в JavaScript.

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

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

По определению, 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();
}

Одна из лучших структур данных для приложения выше - это фильтр Блума, который очень хорош для больших объемов данных. Тем не менее, вы можете применить использование WeakSet и для этой цели.

"Слабый" набор или карта полезны, когда вам нужно сохранить произвольную коллекцию вещей, но вы не хотите, чтобы их присутствие в коллекции не препятствовало сборке мусора, если память переполнена. (Если сборка мусора происходит, "собранные" объекты бесшумно исчезают из коллекции, так что вы можете фактически сказать, исчезли ли они.)

Они отлично подходят, например, для использования в качестве кэша для поиска в стороне: "Я уже получил эту запись, недавно?" Каждый раз, когда вы что-то извлекаете, помещаете это в карту, зная, что сборщик мусора JavaScript будет отвечать за "обрезку списка" для вас, и что он будет делать это автоматически в ответ на преобладающие условия памяти (которые вы можете ' т разумно предвидеть).

Единственным недостатком является то, что эти типы не являются "перечислимыми". Вы не можете перебирать список записей - вероятно, потому что это, скорее всего, "коснется" этих записей и, таким образом, приведет к потере цели. Но это небольшая цена, которую можно заплатить (и вы можете, если нужно, "обойти это").

WeakSet - это упрощение WeakMap, для которого ваше значение всегда будет иметь логическое значение true. Это позволяет вам помечать объекты 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.
};

Ваша консоль, вероятно, неправильно отображала содержимое из-за того, что сборка мусора еще не состоялась. Поэтому, поскольку объект не был собран сборщиком мусора, он покажет объект все еще в уязвимом положении.

Если вы действительно хотите увидеть, имеет ли слабый набор ссылку на определенный объект, используйте 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));

Я отвечу на первую часть и постараюсь не запутать вас в дальнейшем.

Сборка мусора разыменованных объектов не наблюдается! Это было бы парадоксом, потому что вам нужна ссылка на объект, чтобы проверить, существует ли он на карте. Но не верьте мне в этом, доверяйте Кайлу Симпсону:https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/es6%20%26%20beyond/ch5.md#weakmaps

Проблема с множеством объяснений, которые я вижу здесь, заключается в том, что они повторно ссылаются на переменную на другой объект или присваивают ему примитивное значение, а затем проверяют, содержит ли WeakMap этот объект или значение в качестве ключа. Конечно же нет! У него никогда не было этого объекта / значения в качестве ключа!

Итак, последний кусок этой головоломки: почему при просмотре WeakMap в консоли все эти объекты все еще отображаются там, даже после того, как вы удалили все ссылки на эти объекты? Поскольку сама консоль хранит постоянные ссылки на эти объекты, чтобы иметь возможность перечислить все ключи в WeakMap, потому что это то, что не может сделать сам WeakMap.

Пока я искал варианты использования Weakset, я нашел следующие моменты:

«WeakSet является слабым, что означает, что ссылки на объекты в WeakSet удерживаются слабо. Если не существует других ссылок на объект, хранящийся в WeakSet, эти объекты могут быть удалены сборщиком мусора».

####################################

Это черные ящики: мы получаем какие-либо данные из WeakSet только в том случае, если у нас есть и WeakSet, и значение.

####################################

Случаи использования:

1 - чтобы избежать ошибок

2 - в целом может быть очень полезно избежать повторного посещения/настройки любого объекта

Ссылка: https://esdiscuss.org/topic/actual-weakset-use-cases

3 - Содержимое WeakSet может быть удалено сборщиком мусора.

4 - Возможность снижения использования памяти.

Ссылка: https://www.geeksforgeeks.org/what-is-the-use-of-a-weakset-object-in-javascript/

####################################

Пример на Weakset: https://exploringjs.com/impatient-js/ch_weaksets.html

Я советую вам узнать больше о слабой концепции в JS: https://blog.logrocket.com/weakmap-weakset-understanding-javascript-weak-references/

Другие вопросы по тегам