突然被一个问题击中时,我正在制作一个循环。 这应该是“正确的方式”:
// code..
$('tr','#my_table').each(function(){
$(this).click(function(){
var show_id = $(this).attr('data-show-id');
// code..
// code..
});
});
// code..
OR
// code..
var show_id = 0; /* HERE */
$('tr','#my_table').each(function(){
$(this).click(function(){
show_id = $(this).attr('data-show-id');
// code..
// code..
});
});
在第一个示例中,我为每个tr
创建了一个新变量show_id
。
在第二个中,我对表中的所有show_id
使用相同的全局tr
,并在每个tr上重新填充它。
所以问题是:无论编程语言如何 - 更好的做法是在每个循环上创建一个新变量,当函数退出或“捕获”整个运行的内存并避免重新创建每个变量时释放该变量时间?
答案 0 :(得分:10)
循环期间不会创建变量。它仅在事件处理程序中需要,它将自己执行。将变量(仅在内部需要)移动到外面有三个问题:
第二点也是你问题的答案:
更好的做法是在每个循环上创建一个新变量,该变量在函数退出时“释放”或“捕获”整个运行的内存并避免每次重新创建变量吗?
一直浪费内存几乎没有意义,创建功能范围很快。将声明从使用变量中移开可能被认为是不好的做法,将它移到不同的范围甚至会引入错误。
如果在具有大内存的计算机上运行,并且创建/删除对象(对所有处理程序保持不变)很慢,则预分配内存是有意义的。
答案 1 :(得分:1)
这完全取决于您需要存在变量的位置。 JS将变量提升到当前范围的顶部(声明的范围)或者如果未声明var,则创建(evil)全局变量。
如果在循环中声明一个var并不重要:
for (var i=0;i<10;i++)
{
var j = 1*2;
}
被翻译成:
var i, j;
for (i=0;i<10;i++)
{
j = 1*2;
}
一些“经验法则”,但是:
(function()
{
'use strict';
//your code here
}());
调试它,直到你暗示 - 全球免费。
在您的示例中,您“提供”在全局范围内声明show_id
之间的选择(好吧,$(document).ready(callback
范围),或click
处理程序内部。没有什么可以阻止你在each
回调中声明变量,这在这种情况下没有太大区别,但这是另一回事。
在JS中,函数都有自己的作用域,并在你需要的作用域中声明一个变量。
话虽如此,只是注意到性能标记,您的代码就像效率一样糟糕。而不是遍历行,并绑定事件处理程序:委托事件:
$('#my_table').on('click','tr',function(e)
{
var show_id = e.target.attr('data-show-id');
});
在此代码中,如果您希望保留show_id
(例如,检查单击下一行的时间),则show_id
将在单击处理程序返回后进行GC操作:< / p>
$('#my_table').on('click','tr',(function (show_id)
{
return function(e)
{
console.log('show_id was: ' + show_id);
show_id = e.target.attr('data-show-id');
console.log('and is now: ' + show_id);
};
}()));
console.log(show_id);//undefined
变量保存在范围内(包含return function
的函数是声明show_id
的范围,但其返回值引用该变量,因此它不是GC。返回函数,我们处于更高的范围,所以我们根本无法访问变量。我们可以做的是暴露它的价值:
var someVar = {};
$('#my_table').on('click','tr',(function (show_id)
{
return function(e)
{
show_id = e.target.attr('data-show-id');
someVar.myTableClicks = show_id;
console.log(someVar.myTableClicks);//value of show_id
};
}()));
console.log(someVar.myTableClicks);//undefined
//after a couple of clicks
console.log(someVar.myTableClicks);//some value
现在,我们可以在任何可以访问show_id
的地方访问someVar
的值。
就个人而言,我更喜欢保留需要某些变量的组代码:
var access = (function(timer)
{
var speed = 100,
begin = function(callback, interval)
{
speed = +(interval) || speed;
timer = setInterval(callback, speed);
},
stop = function()
{
clearInterval(timer);
};
return {start: start, stop: stop};
}());
在此示例中,start
和stop
函数都需要访问timer
var,但我不希望外部的任何代码混淆timer
的价值,所以我只暴露这些功能。 AFAIK,回调参数函数可以包含timer
或speed
引用,但它们不会引用我试图屏蔽的speed
和timer
变量,因为回调根据定义,函数将在另一个范围内声明,因此不能访问此范围。即便如此,如果你想绝对确定,你总是可以这样做:
var access = (function(timer)
{
var speed = 100,
begin = function(callback, interval)
{
speed = +(interval) || speed;
timer = (function(timer, speed)
{//masks timer & speed from the higher scope
return setInterval(callback, speed);
}('abc', 'def'));//assign dummy values
timer = setInterval(callback, speed);
},
stop = function()
{
clearInterval(timer);
};
return {start: start, stop: stop};
}());
答案 2 :(得分:0)
取决于您的要求。
第一个例子:
$('tr','#my_table').each(function(){
$(this).click(function(){
var show_id = $(this).attr('data-show-id');
// code..
});
});
变量是本地,可以在与.each或点击绑定的匿名函数中使用。
第二个例子:
var show_id = 0; /* HERE */
$('tr','#my_table').each(function(){
$(this).click(function(){
show_id = $(this).attr('data-show-id');
// code..
// code..
});
});
此变量为全局,因此其范围在整个脚本中有效!!!
答案 3 :(得分:0)
Personaly我会用:
$("tr","#my_table").each(function(){
$(this).on("click", function(){
var $this = $(this);
var show_id = $this.data("show-id");
// code..
// code..
});
});
答案 4 :(得分:0)
所有变量的内存将在方法的入口处分配,因此这两个示例是等效的。第二个例子更好,因为它更安全,因为变量的范围有限(不会在循环外意外使用变量)。