admin管理员组

文章数量:1296240

I was making a loop when suddenly got hit by a question. Which is supposed to be "the right way":

    // 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..
        });
    });

In the first example I create for each tr a new variable show_id. In the second I use the same global show_id for all of the tr's in the table and I repopulate it on each tr.

So the question wold be: REGARDLESS of the programing language - Is it better practice to create on each loop a new variable which be released when the function exits or "catch" the memory for the entire run and avoid recreating a variable each time?

I was making a loop when suddenly got hit by a question. Which is supposed to be "the right way":

    // 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..
        });
    });

In the first example I create for each tr a new variable show_id. In the second I use the same global show_id for all of the tr's in the table and I repopulate it on each tr.

So the question wold be: REGARDLESS of the programing language - Is it better practice to create on each loop a new variable which be released when the function exits or "catch" the memory for the entire run and avoid recreating a variable each time?

Share Improve this question asked Jul 30, 2013 at 12:30 PhoenixPhoenix 1,2762 gold badges17 silver badges25 bronze badges 6
  • I believe you are supposed to define it first, then use it in the code later. – Adam Commented Jul 30, 2013 at 12:34
  • 4 Unrelated to what you asked, you don't need that .each() at all. You can say $('tr','#my_table').click(function() { ... }); – nnnnnn Commented Jul 30, 2013 at 12:35
  • 1 @nnnnnn aware of that. Needed to make my example clear.. Thnx for the clarification. – Phoenix Commented Jul 30, 2013 at 12:36
  • 2 I don't think we can really disregard the programming language here. In C++, for example, if the variable contains an instance of a user-defined class whose constructor and/or destructor is costly to run, then you will definitely want to put it in the outermost scope you can manage. But in, say, Javascript, it won't make any difference most of the time. – Frédéric Hamidi Commented Jul 30, 2013 at 12:37
  • It's good to create the variable outside, if you are using it for sharing datas between multiple event handlers. – Stano Commented Jul 30, 2013 at 12:37
 |  Show 1 more ment

5 Answers 5

Reset to default 11

The variable is not created during the loop. It is needed in the event handler only, which will be executed on its own. Moving the variable (when it's only needed inside) outside has three problems:

  • access to a higher-scoped variable is a littlebit slower
  • garbage collection does not collect the value (not memory-efficient)
  • possible trouble when async behavior in the event handler accesses the variable but the handler is invoked multiple times

The second point is also the answer to your question:

Is it better practice to create on each loop a new variable which be released when the function exits or "catch" the memory for the entire run and avoid recreating a variable each time?

It hardly makes sense to waste the memory for the entire time, creating the function scope is fast. Moving the declaration away from the use of the variable can be considered bad practise, moving it to a different scope even can introduce errors.

Preallocating the memory would make sense if you run on a machine with big memory, and creating/deleting the object (that stays constant for all handlers) is slow.

It all depends, really, on where you need that variable to exist. JS will hoist the variable to the top of the current scope (the one in which is was declared) or create an (evil) global if the var wasn't declared.

It doesn't really matter if you declare a var inside a loop:

for (var i=0;i<10;i++)
{
    var j = 1*2;
}

is translated into:

var i, j;
for (i=0;i<10;i++)
{
    j = 1*2;
}

A couple of "rules of thumb", though:

  • if you're using a global variable, you're probably making a mistake
  • if you're declaring a variable inside a loop, you probably don't need that variable anyway
  • if you're not declaring variables, try doing this with your script:

(function()
{
    'use strict';
    //your code here
}());

And debug it until you're implied-global-free.

In your example, you're "offering" the choice between show_id being declared in the global scope (well, $(document).ready(callback scope anyways), or inside the click handler. There's nothing to prevent you from declaring the variable in the each callback either, which wouldn't make much difference in this case, but that's a different matter.

In JS, functions all have their own scope, and you declare a variable in the scope you need it.

Having said that, and just noticing your performance tag, your code is about as bad as it gets in terms of efficiency. Instead of looping over the rows, and binding event handlers all over: delegate the event:

$('#my_table').on('click','tr',function(e)
{
    var show_id = e.target.attr('data-show-id');
});

In this code, show_id will be GC'ed after the click handler has returned, if you want the show_id to be preserved, for example, to check when the next row is clicked:

$('#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

The variable is kept in scope (the function wrapped around the return function is the scope in which show_id as declared, but its return value references that variable, so it's not GC'ed. Outside that returned function, we're in a higher scope, so we can't access the variable at all. What we can do is expose its value:

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

Now, we can access the value of show_id anywhere we can access someVar.

Personally, I prefer to keep group code that require some variable to be available:

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

In this example, both the start and stop functions require access to the timer var, but I don't want any code from outside to mess with timer's value, so I'm only exposing those functions. AFAIK, the callback argument function can contain timer or speed references, but they won't reference the speed and timer vars I'm trying to shield, because the callback function will, by definition be declared in another scope, and therefore it can't have access to this scope. Even so, if you want to be absolutely sure, you can always do this:

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

Personaly I would use:

    $("tr","#my_table").each(function(){
        $(this).on("click", function(){
             var $this = $(this);                
             var show_id = $this.data("show-id");
            // code..
            // code..
        });
    });
  1. Use on("click", function() {...}); instead of .click()
  2. var $this = $(this) is remended in case you will use it further down in your code else you can ignore it
  3. show_id in this case will not be accessible outside of this scope.
  4. To acces data-* atributes you should use data("-") instead of attr("-")

Memory for all of the variables will be allocated at the entrance of a method, so that the two examples are equivalent. The second example is better because it will be more secure because of the limited scope for variables (will not accidentally use a variable outside the loop).

Depends on your requirements.

First example:

$('tr','#my_table').each(function(){
        $(this).click(function(){
            var show_id = $(this).attr('data-show-id');
            // code..
        });
    });

Variable is local and can be used inside anonymous function binded with .each or click.

Second Example:

var show_id = 0; /* HERE */ 
    $('tr','#my_table').each(function(){
        $(this).click(function(){
            show_id = $(this).attr('data-show-id');
            // code..
            // code..
        });
    });

Here the variable is Global and thus its scope is valid in the entire script!!!

本文标签: javascriptThe right way of using a variableinside or outside a function loopStack Overflow