console.log('Hello');
};
};
constsayHello = outer; // contAIns definition of the function inner
functionrepeat(fn, num) {
for(leti = 0; i < num; i++){
fn;
}
}
repeat(sayHello, 10); // each sayHello call pushes another 'Hello' to the potentiallyHugeArray
// now imagine repeat(sayHello, 100000)
在这个例子中,potentiallyHugeArray 从未被任何函数返回,也无法被访问,但它的大小会随着调用 inner 方法的次数而增长 。
3. 定时器
在 Java 中,使用使用 setTimeout 或 setInterval 函数引用对象是防止对象被垃圾回收的最常见方法 。当在代码中设置循环定时器(可以使 setTimeout 表现得像 setInterval,即使其递归)时,只要回调可调用,定时器回调对象的引用就会永远保持活动状态 。
例如下面的这段代码,只有在移除定时器后,data 对象才会被垃圾回收 。在没有移除 setInterval 之前 , 它永远不会被删除,并且 data.hugeString 会一直保留在内存中,直到应用程序停止 。
functionsetCallback{
constdata = https://www.isolves.com/it/cxkf/yy/js/2023-10-27/{
counter: 0,
hugeString: newArray(100000).join('x')
};
returnfunctioncb{
data.counter++; // data object is now part of the callback's scope
console.log(data.counter);
}
}
setInterval(setCallback, 1000); // how do we stop it?
那么应该如何避免上述这种情况的发生呢?可以从以下两个方法入手:
- 注意定时器回调引用的对象 。
- 必要时取消定时器 。
functionsetCallback{
// 'unpacking' the data object
letcounter = 0;
consthugeString = newArray(100000).join('x'); // gets removed when the setCallback returns
returnfunctioncb{
counter++; // only counter is part of the callback's scope
console.log(counter);
}
}
consttimerId = setInterval(setCallback, 1000); // saving the interval ID
// doing something ...
clearInterval(timerId); // stopping the timer i.e. if button pressed
4. 事件监听
活动的事件监听器会阻止其范围内的所有变量被回收 。一旦添加,事件监听器会一直生效 , 直到下面两种情况的发生:
- 通过 removeEventListener 移除 。
- 相关联的 DOM 元素被移除 。
consthugeString = newArray(100000).join('x');
document.addEventListener('keyup', function{ // anonymous inline function - can't remove it
doSomething(hugeString); // hugeString is now forever kept in the callback's scope
});
那么如何避免这种情况呢?可以通过 removeEventListener 释放监听器:
functionlistener{
doSomething(hugeString);
}
document.addEventListener('keyup', listener); // named function can be referenced here...
document.removeEventListener('keyup', listener); // ...and here
如果事件监听器只需要运行一次,addEventListener 可以带有第三个参数,一个提供附加选项的对象 。只要将 {once: true} 作为第三个参数传递给 addEventListener , 监听器将在事件处理一次后自动删除 。
document.addEventListener('keyup', functionlistener{
doSomething(hugeString);
}, {once: true}); // listener will be removed after running once
5. 缓存
如果不断向缓存中添加内容,而未使用的对象也没有移除,也没有限制缓存的大小,那么缓存的大小就会无限增长:
letuser_1 = { name: "Peter", id: 12345};
letuser_2 = { name: "Mark", id: 54321};
constmapCache = newMap;
functioncache(obj){
if(!mapCache.has(obj)){
constvalue =https://www.isolves.com/it/cxkf/yy/js/2023-10-27/ `${obj.name}has an id of ${obj.id}`;
mapCache.set(obj, value);
return[value, 'computed'];
}
return[mapCache.get(obj), 'cached'];
}
cache(user_1); // ['Peter has an id of 12345', 'computed']
cache(user_1); // ['Peter has an id of 12345', 'cached']
cache(user_2); // ['Mark has an id of 54321', 'computed']
console.log(mapCache); // ((…) => "Peter has an id of 12345", (…) => "Mark has an id of 54321")
推荐阅读
- AI基础软件:如何自主构建大+小模型?
- 如何将本地jar文件打包到 springboot 执行jar文件中
- 如何使用 Python 和 python-docx 库读取、写入和操作 Word 文件
- 如何使用GPT作为SQL查询引擎的自然语言
- 恶犬咬伤后如何处理?怎么接种狂犬疫苗?十问十答来了
- 个人养老金制度出炉!我们该如何解读和面对?
- 如何通过规划提高自己的养老金水平?
- 小米电视如何彻底关闭,小米手机相机怎么关闭美颜
- 钉钉如何填写每日健康上报,钉钉员工每日健康打卡怎么设置
- 吃一什么长一智,为什么老是要吃一堑才长一智怎么避免这个问题