предисловие
Начнем с характеристик WeakMap, а затем поговорим о некоторых сценариях применения WeakMap.
характеристика
1. WeakMap принимает только объекты в качестве ключей
const map = new WeakMap();
map.set(1, 2);
// TypeError: Invalid value used as weak map key
map.set(null, 2);
// TypeError: Invalid value used as weak map key
2. Объект, на который ссылается имя ключа WeakMap, является слабой ссылкой.
Это предложение на самом деле очень озадачивает меня. Лично я думаю, что то, что на самом деле хочет выразить это предложение, должно быть:
WeakMaps hold "weak" references to key objects,
Перевод должен заключаться в том, что WeakMaps поддерживает слабую ссылку на объект, на который ссылается имя ключа.
Сначала поговорим о слабых ссылках:
В компьютерном программировании слабая ссылка противоположна сильной ссылке и относится к ссылке, которая не может гарантировать, что объект, на который она ссылается, не будет утилизирован сборщиком мусора. Объект считается недоступным (или слабодоступным), если на него ссылаются только слабые ссылки, и поэтому его можно собрать в любое время.
В JavaScript мы вообще создаем объект, построенный на сильной ссылке:
var obj = new Object();
только если мы вручную установимobj = null
Только когда возможно переработать объект, на который ссылается obj.
И если мы сможем создать объект со слабой ссылкой:
// 假设可以这样创建一个
var obj = new WeakObject();
Нам не нужно ничего делать, просто спокойно подождите, пока выполнится механизм сборки мусора, и объект, на который ссылается obj, будет собран.
Давайте посмотрим на это снова:
WeakMaps поддерживает слабые ссылки на объекты, на которые ссылаются ключи.
Обычно давайте возьмем пример:
const key = new Array(5 * 1024 * 1024);
const arr = [
[key, 1]
];
Таким образом, мы фактически создаем сильную ссылку на объект, на который ссылается ключ (мы предполагаем, что реальный объект называется Obj).
поэтому, когда вы устанавливаетеkey = null
, удаляется только сильная ссылка key на Obj, но сильная ссылка arr на Obj не удаляется, поэтому Obj не будет переработан.
Тип карты аналогичен:
let map = new Map();
let key = new Array(5 * 1024 * 1024);
// 建立了 map 对 key 所引用对象的强引用
map.set(key, 1);
// key = null 不会导致 key 的原引用对象被回收
key = null;
Мы можем продемонстрировать эту проблему с Node:
// 允许手动执行垃圾回收机制
node --expose-gc
global.gc();
// 返回 Nodejs 的内存占用情况,单位是 bytes
process.memoryUsage(); // heapUsed: 4640360 ≈ 4.4M
let map = new Map();
let key = new Array(5 * 1024 * 1024);
map.set(key, 1);
global.gc();
process.memoryUsage(); // heapUsed: 46751472 注意这里大约是 44.6M
key = null;
global.gc();
process.memoryUsage(); // heapUsed: 46754648 ≈ 44.6M
// 这句话其实是无用的,因为 key 已经是 null 了
map.delete(key);
global.gc();
process.memoryUsage(); // heapUsed: 46755856 ≈ 44.6M
Если вы хотите, чтобы Obj был переработан, вам нужно сначалаdelete(key)
после этогоkey = null
:
let map = new Map();
let key = new Array(5 * 1024 * 1024);
map.set(key, 1);
map.delete(key);
key = null;
Мы по-прежнему доказываем это через Node:
node --expose-gc
global.gc();
process.memoryUsage(); // heapUsed: 4638376 ≈ 4.4M
let map = new Map();
let key = new Array(5 * 1024 * 1024);
map.set(key, 1);
global.gc();
process.memoryUsage(); // heapUsed: 46727816 ≈ 44.6M
map.delete(key);
global.gc();
process.memoryUsage(); // heapUsed: 46748352 ≈ 44.6M
key = null;
global.gc();
process.memoryUsage(); // heapUsed: 4808064 ≈ 4.6M
На этот раз мы поговорим о WeakMap:
const wm = new WeakMap();
let key = new Array(5 * 1024 * 1024);
wm.set(key, 1);
key = null;
когда мы устанавливаемwm.set(key, 1)
Когда на самом деле устанавливается слабая ссылка wm на объект, на который ссылается ключ, но посколькуlet key = new Array(5 * 1024 * 1024)
Устанавливается сильная ссылка на ссылочный объект по ключу, и ссылочный объект не будет переработан, но когда мы установимkey = null
Когда имеется только слабая ссылка wm на объект, на который указывает ссылка, объект, на который делается ссылка, будет переработан при выполнении следующего механизма сборки мусора.
Давайте докажем это с Node:
node --expose-gc
global.gc();
process.memoryUsage(); // heapUsed: 4638992 ≈ 4.4M
const wm = new WeakMap();
let key = new Array(5 * 1024 * 1024);
wm.set(key, 1);
global.gc();
process.memoryUsage(); // heapUsed: 46776176 ≈ 44.6M
key = null;
global.gc();
process.memoryUsage(); // heapUsed: 4800792 ≈ 4.6M
Таким образом, WeakMap может избавить вас от необходимости вручную удалять данные, связанные с объектами, поэтому вы можете рассмотреть возможность использования WeakMap, когда вы не можете или не хотите контролировать жизненный цикл связанных данных.
Чтобы обобщить характеристики этой слабой ссылки, WeakMaps поддерживает слабую ссылку на объект, на который ссылается имя ключа, то есть механизм сборки мусора не принимает во внимание эту ссылку. Как только другие ссылки на указанный объект очищаются, механизм сборки мусора освобождает память, занятую объектом. То есть, как только он больше не нужен, объект имя-ключ и соответствующая пара ключ-значение в WeakMap автоматически исчезнут, и нет необходимости вручную удалять ссылку.
Именно из-за этой особенности количество членов в WeakMap зависит от того, работает механизм сборки мусора или нет, очень вероятно, что количество членов разное до и после запуска, а когда работает механизм сборки мусора непредсказуем, поэтому ES6 указывает, что WeakMap не может быть пройден.
Таким образом, WeakMap не похож на Map.Во-первых, здесь нет операции обхода (то есть методов keys(), values() и entry()), нет атрибута размера и нет метода очистки, поэтому WeakMap имеет только четыре доступных метода: получить(), установить(), имеет(), удалить().
заявление
1. Сохраните соответствующие данные в объекте DOM.
При традиционном использовании jQuery мы бы передали$.data()
Метод хранит соответствующую информацию об объекте DOM (например, хранит информацию об идентификаторе публикации в элементе кнопки удаления). jQuery внутренне использует объект для управления DOM и соответствующими данными. Когда вы удаляете элемент DOM, объект DOM установлено пустое. , связанные данные не будут удалены, вы должны сделать это вручную$.removeData()
способ удаления связанных данных, WeakMap может упростить эту операцию:
let wm = new WeakMap(), element = document.querySelector(".element");
wm.set(element, "data");
let value = wm.get(elemet);
console.log(value); // data
element.parentNode.removeChild(element);
element = null;
2. Кэш данных
Из предыдущего примера мы также можем видеть, что когда нам нужно связать объекты и данные, например, сохранить некоторые атрибуты без изменения исходного объекта или сохранить некоторые вычисленные значения в соответствии с объектом и т. д., но не хотим управлять эти данные. Мертвый или живой — хорошее время, чтобы подумать об использовании WeakMap. Кэширование данных — очень хороший пример:
const cache = new WeakMap();
function countOwnKeys(obj) {
if (cache.has(obj)) {
console.log('Cached');
return cache.get(obj);
} else {
console.log('Computed');
const count = Object.keys(obj).length;
cache.set(obj, count);
return count;
}
}
3. Частная собственность
WeakMap также можно использовать для реализации приватных переменных, но есть много способов реализации приватных переменных в ES6, это только один из них:
const privateData = new WeakMap();
class Person {
constructor(name, age) {
privateData.set(this, { name: name, age: age });
}
getName() {
return privateData.get(this).name;
}
getAge() {
return privateData.get(this).age;
}
}
export default Person;
серия ES6
Адрес каталога серии ES6:GitHub.com/ в настоящее время имеет бриз…
Ожидается, что в серии ES6 будет написано около 20 статей, направленных на углубление понимания некоторых точек знаний ES6, с акцентом на область действия на уровне блоков, шаблоны меток, функции стрелок, реализацию моделирования символов, наборов, карт и обещаний, схему загрузки модулей, асинхронность. обработка и т.п. содержание.
Если есть какие-либо ошибки или неточности, пожалуйста, поправьте меня, большое спасибо. Если вам нравится или у вас есть вдохновение, добро пожаловать в звезду, что также является поощрением для автора.