我遇到了一些奇怪的事情,我想和你分享,这样你就可以帮助我沮丧。 (我花了一段时间才弄清楚出了什么问题)
我想创建一个递归函数,在嵌套的<ul>
元素上呈现树状数据结构。
数据结构采用以下形式:
var contents = [
{
name : 'test',
contents : [
{
name : 'test > test 1'
},
{
name : 'test > test 2'
},
{
name : 'test > test 3'
}
]
},
{
name : 'test 2'
}
];
我在代码块上添加了我的代码:
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
之后的变量dummy.recursive
在第一个元素的内容上运行时不再是0而是2.这意味着虽然i
是私有的上下文正在被递归函数所取代。
我还添加了一个jsfiddle来解释这里的问题:http://jsfiddle.net/MWQJC/2/
问题在于变量i
未通过在函数开头执行var i = 0
而显式声明。 (如下图所示:http://jsfiddle.net/h8gtd/1/)
默认情况下,在对象范围内创建所有未访问的未声明变量。是这样吗?
答案 0 :(得分:2)
默认情况下,每个未访问的变量都是正常的 在对象范围中创建。是这样吗?
没有。
每次访问(读取)变量的值时,JS引擎都会尝试在当前作用域中查找变量,然后在当前作用域的外部作用域中查找该作用域的外部作用域等,直到您找到全球范围。此时如果仍未声明变量,则抛出错误。
当您为变量设置(写入)值时,将遵循相同的过程,最后一步是不同的。如果甚至在全局范围内尚未声明变量,则将在全局范围中创建具有该名称的变量。
例如:
// 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
在您的特定示例中,您是正确的,问题是i
尚未在递归函数中声明为变量,因此该递归函数的所有调用将使用相同的{{1}在某些外部作用域或全局作用域中定义的变量。
答案 1 :(得分:1)
您要求closure
。这是精心解释的here。
报价:
这是一个关闭。函数不必为了返回而返回 叫封闭。只需访问您眼前的变量即可 词法范围创造了一个闭包。
function foo(x) { var tmp = 3; return function (y) { alert(x + y + (++tmp)); } } var bar = foo(2); // bar is now a closure. bar(10);
上面的功能也会提醒16,因为bar仍然可以参考 x和tmp,即使它不再直接在范围内。