深入JavaScript教你内存泄漏如何防范( 三 )

上面的例子中,缓存依然保留了user_1 的数据 。因此我们需要把不再使用的数据从缓存中删除 。可能的解决方案: 为了解决这个问题,可以使用 WeakMap 。WeakMap 是一种数据结构,它只用对象作为键,并保持对象键的弱引用,如果这个对象被置空了,相关的键值对会被 GC 自动回收 。
let user_1 = { name: "Kayson", id: 12345 };let user_2 = { name: "Jerry", id: 54321 };const weakMapCache = new WeakMap();function cache(obj){    // 代码跟前一个例子相同,只不过用的是 weakMapCache    return [weakMapCache.get(obj), 'cached'];}cache(user_1); // ['Kayson has an id of 12345', 'computed']cache(user_2); // ['Jerry has an id of 54321', 'computed']console.log(weakMapCache); // ((…) => "Kayson has an id of 12345", (…) => "Jerry has an id of 54321"}user_1 = null; // Garbage Collectorconsole.log(weakMapCache); // ((…) => "Jerry has an id of 54321") - 第一条记录已被 GC 删除6 分离的 DOM 元素如果 DOM 节点被 JavaScript 代码直接引用,即使从 DOM 树分离,也不会被 GC 回收 。
下面的例子中,removeChild() 达不到预期效果,堆快照会显示htmlDivElement处于分离状态,因为有个变量指向了这个div 。
function createElement() {    const div = document.createElement('div');    div.id = 'detached';    return div;}// 即使调用了deleteElement() ,依然保存着 DOM 元素的引用const detachedDiv = createElement();document.body.AppendChild(detachedDiv);function deleteElement() {document.body.removeChild(document.getElementById('detached'));}deleteElement(); // 堆快照显示: detached div#detached如何避免: 一种方法是把DOM 引用限制为局部作用域 。
function createElement() {...} // // DOM 引用位于函数作用域内function appendElement() {    const detachedDiv = createElement();    document.body.appendChild(detachedDiv);}appendElement();function deleteElement() {     document.body.removeChild(document.getElementById('detached'));}deleteElement();总结对于重要的前端应用,定位和解决 JavaScript 内存问题是一项颇具挑战性的任务 。因此,理解典型的内存泄露原因,从而在源头上避免,是做好内存管理的必要工作 。希望本文总结的造成内存泄漏的六大来源对你有所启发,在写代码的时候有所防范 。





推荐阅读