Объект WeakSet
Объект WeakSet
во многом похож на обычное множество. Он также может хранить только уникальные значения, но каждый его элемент должен представлять объект.
Для создания объекта WeakSet
используется его конструктор, в который можно передать начальные значения:
// пустой WeakSet
const weakSet1 = new WeakSet();
// инициализация начальными значениями
const weakSet2 = new WeakSet([{name:"Tom", age: 37}, {name:"Alice", age: 34}]);
Для инициализации как в случае с объектом Set
в конструктор передается массив, но данный массив содержит именно объекты, а не скалярные значения, типа чисел или строк.
Для добавления данных в WeakSet
применяется метод add()
:
const weakSet = new WeakSet();
weakSet.add({lang: "JavaScript"});
weakSet.add({lang: "TypeScript"});
// так нельзя - 34 - число, а не объект
// weakSet.add(34);
// {{lang: "JavaScript"}, {lang: "TypeScript"}}
console.log(weakSet);
Причем опять же добавить мы можем только объект, а не скалярные значения типа чисел или строк.
Для удаления применяется метод delete()
, в который передается ссылка на удаляемый объект:
const weakSet = new WeakSet();
const js = {lang: "JavaScript"};
const ts = {lang: "TypeScript"};
weakSet.add(js);
weakSet.add(ts);
weakSet.delete(js);
// {{lang: "TypeScript"}}
console.log(weakSet);
Если надо проверить, имеется ли объект в WeakSet
, то можно использовать метод has()
, который возвращает true
при наличии объекта:
const js = {lang: "JavaScript"};
const ts = {lang: "TypeScript"};
const java = {lang: "Java"};
const weakSet = new WeakSet([js, ts]);
// true
console.log(weakSet.has(ts));
// false
console.log(weakSet.has(java));
Перебор WeakSet
WeakSet
не поддерживает перебор ни с помощью метода ForEach
, которого у WeakSet
нет, ни с помощью цикла for
. Если мы попробуем перебрать WeakSet
через цикл for..of
:
const weakSet = new WeakSet([
{lang: "JavaScript"},
{lang: "TypeScript"},
{lang: "Java"}
]);
for(item in weakSet){
console.log(item);
}
мы получим ошибку:
Uncaught TypeError: weakSet is not iterable
Слабые ссылки
Объекты передаются в WeakSet
по ссылке, когда объект перестае существовать в силу различных причин, он удаляется из WeakSet
, рассмотрим следующий пример:
let js = {lang: "JavaScript"};
let ts = {lang: "TypeScript"};
const weakSet = new WeakSet([js, ts]);
js = null;
// {{lang: "JavaScript"}, {lang: "TypeScript"}}
console.log(weakSet);
console.log("Некоторая работа");
const timerId = setTimeout(function(){
// {{lang: "TypeScript"}}
console.log(weakSet);
clearTimeout(timerId);
}, 9000);
В данном случае сначала объект WeakSet
хранит ссылки на два объекта: js
и ts
. Далее мы устанавливаем значение для переменной js
в null
.
Это приведет к тому, что спустя некоторое время начальное значение этой переменной будет удалено сборщиком мусора JavaScript.
js = null;
Причем если сразу после этого мы посмотрим на содержимое weakSet
, увидим что объект js
в нем еще присутствует. Однако спустя некоторое время ссылка будет удалена из weakSet
. Для эмуляции прошествия времени здесь используется функция setTimeout
, которая выводит на консоль содержимое weakSet
через 9000 секунд (конкретный период времени, через который сборщик мусора удалит значение, может отличаться).
Теперь сравним с тем, что произойдет если вместо WeakSet
использовать Set
:
let js = {lang: "JavaScript"};
let ts = {lang: "TypeScript"};
const set = new Set([js, ts]);
js = null;
// Set(2) {{lang: "JavaScript"}, {lang: "TypeScript"}}
console.log(set);
console.log("Некоторая работа");
const timerId = setTimeout(function(){
// Set(2){{lang: "JavaScript"}, {lang: "TypeScript"}}
console.log(set);
clearTimeout(timerId);
}, 10000);
В случае с Set
даже спустя некоторое время мы увидим, что в объекте Set
до сих пор присутствует объект, для которого было установлено значение null
.