使用变量的正确方法 - 在函数循环内部或外部

时间:2013-07-30 12:30:51

标签: javascript jquery performance

突然被一个问题击中时,我正在制作一个循环。 这应该是“正确的方式”:

    // 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上重新填充它。

所以问题是:无论编程语言如何 - 更好的做法是在每个循环上创建一个新变量,当函数退出或“捕获”整个运行的内存并避免重新创建每个变量时释放该变量时间?

5 个答案:

答案 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};
}());

在此示例中,startstop函数都需要访问timer var,但我不希望外部的任何代码混淆timer的价值,所以我只暴露这些功能。 AFAIK,回调参数函数可以包含timerspeed引用,但它们不会引用我试图屏蔽的speedtimer变量,因为回调根据定义,函数将在另一个范围内声明,因此不能访问此范围。即便如此,如果你想绝对确定,你总是可以这样做:

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..
        });
    });
  1. 使用on(“click”,function(){...});而不是.click()
  2. var $ this = $(this)建议您在代码中进一步使用它,否则可以忽略它
  3. 在这种情况下,
  4. show_id将无法在此范围之外访问。
  5. 要访问data- * atributes,您应该使用数据(“ - ”)而不是attr(“ - ”)

答案 4 :(得分:0)

所有变量的内存将在方法的入口处分配,因此这两个示例是等效的。第二个例子更好,因为它更安全,因为变量的范围有限(不会在循环外意外使用变量)。