views:

87

answers:

2

I'm using jQuery, building a table through a loop. I thought the best way of doing this would be to create an array then do $(blah).html(table);

var settings_table = '<open the table>';
  $.each(settings, function(i, val){
    var settings_table = settings_table+'<put stuff in it>';
  });
  var settings_table = settings_table+'<close it>';
  $('#rscc_opts').html(settings_table);

But this isn't working. I'm assuming I'm doing it wrong. Or could you suggest a better solution? My array is formed like:

var settings = [
  {
    var1: 'foo',
    var2: 'foo',
  },
  {
    var1: 'foo',
    var2: 'foo',
  }
];
+4  A: 

Major problem here.

Every time you say "var settings_table", you shadow the variable. Get rid of the "var" keyword on all but the first declaration of settings_table.

Stefan Kendall
Thank you. Didn't know it would overwrite it. Thought it might work like PHP.
Ben Shelock
@Ben It's tricky, because even though the code looks similar to what you might do in PHP, it is really completely different. In PHP, you are doing something more akin to a for(int i =0; i < length; i++). The code you are using is a feature of functional languages. What you are actually doing is saying "iterate over each member, and pass it to this anonymous function". This function behaves much like a regularly declared function - it has its *own* variables. And so when you say "var settings_table", that variable is completely independent of the one above. You are not "overwriting" it.
Matt
Not really. Variable is **declared once**, upon entering function's execution context and before any other statements in function's body are evaluated. Fwiw, **function declarations** are instantiated at that very same time, also before actual evaluation. Later on, during loop, there's merely an assignment going on.
kangax
@kangax But by re-using the "var" declaration on the anonymous function, aren't you in effect create a scope variable for that function, and therefore overriding visibility to the closured variable?
Matt
@Matt Yes absolutely. inner `settings_table` shadows outer one in this case. I only wanted to explain that mere occurrence of `var` (in, say, blocks) does not declare variables; and that variables are always declared once for function execution ;)
kangax
I changed "overwrite" to "shadow." All comments are now invalid!
Stefan Kendall
A: 

To expand on iftrue's answer:

The first time you declare a variable, if you do not specify "var", you are stating it is a global variable.

If you use the "var" keyword, that variable is "scoped" to that particular function. That means its data only accessable by that code inside that function. That means nothing outside that function will have access to that variable. Another function could define the same variable with the same name, and it could store a completely different value.

$.each(settings, function(i, val){
  var settings_table = settings_table+'<put stuff in it>';
});

The trick here is that you are defining a new, anonymous function for use by the iterator. This function has its own scope (it's own personal data). That means that by declaring "var settings_table", you are saying "create a brand new variable, specific to this function". So, what you are in effect doing is assigning the table data to a brand new variable, and then losing the data on the next iteration of the loop. This might be more clear if we were to re-write this as:

function BuildTable(i, val){
  var settings_table = settings_table+'<put stuff in it>';
}

$.each(settings, BuildTable);

What you really want to do is something that can be a little tricky, and it's called a "closure". Closures are an advanced javascript topic. But, in essense, what you are doing is saying "Hey, I want to let this anonymous function have access to my personal data"

In your case, what you want to do is:

var settings_table = '<open the table>';
$.each(settings, function(i, val){
  settings_table = settings_table+'<put stuff in it>';
});

settings_table = settings_table+'<close it>';
$('#rscc_opts').html(settings_table);
Matt