Reputation: 5174
I came across something strange, and I wanted to share it with you so that you could help to my frustration. (it took me a while to figure out what was wrong)
I wanted to create a recursive function that would render a tree like data structure on a nested <ul>
element.
The data structure was in this form:
var contents = [
{
name : 'test',
contents : [
{
name : 'test > test 1'
},
{
name : 'test > test 2'
},
{
name : 'test > test 3'
}
]
},
{
name : 'test 2'
}
];
I added my code on a object block as such:
var dummy = {
do : function() {
var element = $('<ul>');
dummy.recursive(element, contents);
$("#content").append(element);
},
recursive : function( element, contents ) {
for( i = 0; i < contents.length; i++ ) {
var item = contents[i];
var li = $('<li> (' + i + ') ' + item.name + '</li>');
if( item.contents && item.contents.length ) {
var ul = $('<ul>');
dummy.recursive(ul, item.contents);
li.append(ul);
}
element.append(li);
}
}
};
I found out that the variable i
after dummy.recursive
had run on the contents of the first element was no longer 0 but instead 2. This means that although i
is in its private context is being replaced by the recursive function.
I've also added a jsfiddle to illustrate the problem here: http://jsfiddle.net/MWQJC/2/
The problem is in the variable i
not being explicitly declared by doing a var i = 0
on the beginning of the function. (As illustrated here: http://jsfiddle.net/h8gtd/1/)
It looks like by default every undeclared variable accessed is being created in the object scope. Is this so?
Upvotes: 0
Views: 111
Reputation: 27833
It looks like by default every undeclared variable accessed is being created in the object scope. Is this so?
No.
Everytime you access (read) the value of a variable, the JS engine attempts to find the variable in the current scope, then in the outer scope of the current scope, then the outer scope of that scope, etc, until you find the global scope. At that point if the variable still hasn't been declared, an error is thrown.
When you set (write) a value to a variable, the same process is followed, with the last step being different. If the variable hasn't been declared even in the global scope, then a variable with that name will be created in the global scope.
Ex:
// global scope
!function() { // scope 1
var x; // comment this line to log 7 instead
!function() { // scope 2
x = 7;
}()
}();
console.log(x) // undefined, because it never reached the global scope
In your particular example, you are correct that the problem is that i
hasn't been declared as a variable in the recursive function, so all the calls of that recursive function will use the same i
variable defined in some outer scope or in the global scope.
EDIT: I kept using the word scope, but forgot to mention that unlike many other languages, JavaScript doesn't have block scope, but has function scope instead.
Upvotes: 2
Reputation: 8090
You are asking for closure
. This is elaborately explained here.
quote:
That is a closure. A function doesn't have to return in order to be called a closure. Simply accessing variables outside of your immediate lexical scope creates a closure.
function foo(x) { var tmp = 3; return function (y) { alert(x + y + (++tmp)); } } var bar = foo(2); // bar is now a closure. bar(10);
The above function will also alert 16, because bar can still refer to x and tmp, even though it is no longer directly inside the scope.
Upvotes: 1