考虑以下代码,该代码创建附加到 web map 中的点的按钮列表。
最初我考虑扩展元素并将点添加为属性,但因为那不是 recommended ,我只是在事件函数中引用该对象。
pointsInMap = [
{
x : 20.2,
y : 15.2,
name : "point1"
},
{
x : 20.2,
y : 15.2,
name : "point2"
},
{
x : 20.2,
y : 15.2,
name : "point3"
}
]
function addZoomToButtons(points){
points.forEach( point => {
const button = document.createElement('button');
button.text = `Zoom to ${point.name}`;
//I'm overwriting this variable 3 times but javascript needs to keep reference to it, where will it be stored since it's outside the event scope?
const pointObj = new Point(point.x, point.y)
button.addEventListener( () => {
myMap.panAndZoomToPoint(pointObj)
})
document.body.appendChild(button);
})
}
addZoomtoButtons(pointsInMap);
上面的代码在性能/内存方面有什么“错误”吗?我觉得有,但我对 Javascript 中的内存管理了解不够,无法弄清楚。
如果没有任何问题,请帮助我理解原因。
在我看来,不仅仅是添加到内存中 3 events
,它还将保留 addZoomToButtons
的 3 个“副本”/forEach
函数作用域,因为它具有 events
的变量要求。
这只是一个小例子,但请考虑事情可能会变得非常大。
代码调用const pointObj = new Point(point.x, point.y)
在事件范围之外 3 次,但它不能仅仅覆盖 pointObj
因为事件引用了它,所以它也不能只是将范围转移到事件内部,所以我假设紧邻事件外部的范围也被不必要地存储。
如果出现问题,设计解决方案的另一种方法是什么?
表达这个问题的另一种方式是如何以正确且推荐的方式将对象引用绑定(bind)到事件?
最佳答案
I'm overwriting this variable 3 times but javascript needs to keep reference to it, where will it be stored since it's outside the event scope?
JS 将其保存在闭包中。什么是闭包?您可能知道prototype
对象,闭包类似,但使用标识符而不是属性。
const obj = {};
obj.__proto__.someProp = "someProp";
console.log(obj.someProp); // logs "someProp"
自 obj
没有自己的someProp
property,JS 沿着原型(prototype)链向上查找其原型(prototype)对象上的 prop。
标识符的情况非常相似。您可以将函数视为具有隐藏的 __closure__
存储来自上层范围的标识符的对象。如果在本地范围内找不到标识符,则检查最近的闭包。如果在那里没有找到,则检查闭包的闭包。
var global = "global";
function f() {
var outer = "outer";
function g() {
var local = "local";
}
};
/*
in g:
g.__localScope__ has one identifier: `local`
g.__closure__ has one identifier: `outer`
g.__closure__.__closure__ is __global_scope__ and has identifier `global`
*/
当你有从其他函数中提取到上层作用域的函数时
function f(k) {
return function g() {
console.log(k);
}
}
const g1 = f(1);
const g2 = f(2);
/*
g1.__closure__ has identifier k that has value: 1
g2.__closure__ also has identifier k but it has value: 2
g1 can't acces k of g2 and vice versa
*/
g1() // 1
g2() // 2
很高兴知道现代 JavaScript 引擎非常高效并且有很多非常聪明的优化。
考虑这段代码:
function f(k) {
const l = "l value";
return function g() {
debugger;
console.log(k);
};
}
f(1)();
事件虽然l
位于 g()
的外部范围内函数未在开发工具的范围面板中列出:
因为g()
内部没有使用这个标识符函数,Chrome JS引擎V8不会将其保留在内存中以节省资源。如果将日志语句更改为 console.log(k, l);
,这两个变量都将在开发工具中可见并可访问:
关于javascript - Javascript 中依赖于其范围之外的变量的函数会导致内存泄漏吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53618507/