请考虑以下代码,该代码创建连接到网络地图中某个点的按钮列表。
最初,我考虑过扩展元素并将点添加为属性,但是由于不是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);
在性能/内存方面,上述代码是否存在“错误”之处?我觉得有,但是我对Java中的内存管理了解不足,无法弄清楚。
如果没有任何问题,请帮助我理解原因。
根据我的观点,它不仅保留了3个events
的内存,而且还保留了addZoomToButtons
/ forEach
函数范围的3个“副本”,因为它具有变量events
的要求。
这只是一个小例子,但请注意事情会变得非常大。
代码在事件范围之外调用了const pointObj = new Point(point.x, point.y)
3次,但是它不能仅仅覆盖pointObj
,因为事件引用了它,也不能仅仅将范围移到事件内部,因此我假设事件外部的范围也被不必要地存储了。
如果出了问题,设计解决方案的另一种方法是什么?
表达此问题的另一种方式是如何以适当且推荐的方式将对象引用绑定到事件?
答案 0 :(得分:1)
我要将此变量覆盖3次,但是javascript需要保留 引用,由于它不在事件中,因此它将存储在哪里 范围?
JS将其封闭。什么是封包?您可能知道prototype
对象,闭包是类似的,但是使用标识符而不是属性。
const obj = {};
obj.__proto__.someProp = "someProp";
console.log(obj.someProp); // logs "someProp"
由于obj
没有自己的someProp
属性,因此JS进入原型链,并在其原型对象上找到了道具。
标识符的过程非常相似。您可以认为函数具有隐藏的__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);
,则两个变量将在开发工具中可见且可访问: