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

Javascript 使用变量的正确方法-在函数循环内部或外部,javascript,jquery,performance,Javascript,Jquery,Performance,我正在兜圈子,突然被一个问题打断了。 这应该是“正确的方式”: 或 在第一个示例中,我为每个tr创建了一个新变量show\u id。 在第二个示例中,我对表中的所有tr使用相同的全局show_id,并在每个tr上重新填充它 因此,问题是:不管编程语言是什么,在每个循环上创建一个新的变量,在函数退出时释放,还是“捕获”整个运行的内存并避免每次重新创建变量,这是更好的做法?这一切都取决于您需要该变量存在的位置。JS将把变量提升到当前作用域的顶部(声明了变量的作用域),或者如果没有声明变量,则创建一个

我正在兜圈子,突然被一个问题打断了。 这应该是“正确的方式”:

在第一个示例中,我为每个
tr
创建了一个新变量
show\u id
。 在第二个示例中,我对表中的所有
tr
使用相同的全局
show_id
,并在每个tr上重新填充它


因此,问题是:不管编程语言是什么,在每个循环上创建一个新的变量,在函数退出时释放,还是“捕获”整个运行的内存并避免每次重新创建变量,这是更好的做法?

这一切都取决于您需要该变量存在的位置。JS将把变量提升到当前作用域的顶部(声明了变量的作用域),或者如果没有声明变量,则创建一个(邪恶的)全局变量

如果在循环中声明一个var,其实并不重要:

for (var i=0;i<10;i++)
{
    var j = 1*2;
}
并调试它,直到你是全球免费的

在您的示例中,您“提供”了在全局作用域中声明
show\u id
之间的选择(好的,
$(document).ready(无论如何,回调
作用域),或在
单击处理程序中。也没有什么可以阻止您在
每个
回调中声明变量,这在本例中没有多大区别,但这是另一回事

在JS中,函数都有自己的作用域,您可以在需要的作用域中声明一个变量

话虽如此,只要注意到您的性能标签,您的代码在效率方面就和它得到的一样差。与其在行上循环,并在所有行上绑定事件处理程序:委托事件:

$('#my_table').on('click','tr',function(e)
{
    var show_id = e.target.attr('data-show-id');
});
在此代码中,如果希望保留
show\u id
,例如,检查单击下一行的时间,则在单击处理程序返回后,
show\u id
将被GC'ed:

$('#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
变量保留在作用域中(围绕
返回函数
的函数是声明的
show_id
的作用域,但其返回值引用该变量,因此它不是GC'ed。在该返回函数之外,我们处于更高的作用域,因此我们根本无法访问该变量。我们可以做的是公开其值:

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
现在,我们可以在任何可以访问
someVar
的地方访问
show\u id
的值

就个人而言,我更喜欢保留需要某些变量可用的组代码:

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
的值,因此我只公开这些函数。好的,回调参数函数可以包含
timer
speed
引用,但是t它们不会引用我试图屏蔽的
速度
计时器
变量,因为根据定义,回调函数将在另一个作用域中声明,因此它无法访问此作用域。即使如此,如果您想绝对确定,您始终可以这样做:

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

该变量不是在循环期间创建的。它仅在事件处理程序中需要,事件处理程序将自行执行。将该变量(仅在内部需要时)移到外部有三个问题:

  • 访问范围更大的变量要慢一些
  • 垃圾收集不收集值(内存效率不高)
  • 事件处理程序中的异步行为访问变量但多次调用该处理程序时可能出现问题
第二点也是你问题的答案:

在每个循环上创建一个新的变量,在函数退出时释放,或者“捕获”整个运行的内存,避免每次重新创建变量,这是更好的做法吗

完全浪费内存是没有意义的,创建函数作用域很快。将声明从变量的使用中移开会被认为是不好的做法,将它移到另一个作用域甚至会导致错误


如果在内存大的机器上运行,那么预先分配内存是有意义的,并且创建/删除对象(对于所有处理程序保持不变)的速度很慢。

取决于您的要求

第一个示例:

$('tr','#my_table').each(function(){
        $(this).click(function(){
            var show_id = $(this).attr('data-show-id');
            // code..
        });
    });
var show_id = 0; /* HERE */ 
    $('tr','#my_table').each(function(){
        $(this).click(function(){
            show_id = $(this).attr('data-show-id');
            // code..
            // code..
        });
    });
变量是局部的,可以在绑定的匿名函数中使用。每个或单击

第二个示例:

$('tr','#my_table').each(function(){
        $(this).click(function(){
            var show_id = $(this).attr('data-show-id');
            // code..
        });
    });
var show_id = 0; /* HERE */ 
    $('tr','#my_table').each(function(){
        $(this).click(function(){
            show_id = $(this).attr('data-show-id');
            // code..
            // code..
        });
    });
这里的变量是全局变量,因此它的作用域在整个脚本中都是有效的!!!

我个人会使用:

    $("tr","#my_table").each(function(){
        $(this).on("click", function(){
             var $this = $(this);                
             var show_id = $this.data("show-id");
            // code..
            // code..
        });
    });
  • 使用on(“click”,function(){…});而不是.click()
  • 建议使用var$this=$(this),以防您在代码中进一步使用它,否则您可以忽略它
  • 在这种情况下,无法在此范围之外访问show_id
  • 要访问数据-*属性,应使用数据(“-”)而不是属性(“-”)

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

    我相信您应该先定义它,然后在代码中使用它。与您要求的内容无关,您根本不需要
    。each()
    。您可以说
    $('tr','#my_table')。单击(function(){…})例如,如果C++中的变量包含了一个用户定义的类的实例,其构造函数和/或析构函数运行成本很高,那么你肯定想把它放到外部。您可以管理的最大范围。但是,比如说,在Javascript中,它在大多数情况下不会产生任何影响。创建它很好
    
    var show_id = 0; /* HERE */ 
        $('tr','#my_table').each(function(){
            $(this).click(function(){
                show_id = $(this).attr('data-show-id');
                // code..
                // code..
            });
        });
    
        $("tr","#my_table").each(function(){
            $(this).on("click", function(){
                 var $this = $(this);                
                 var show_id = $this.data("show-id");
                // code..
                // code..
            });
        });