编辑:
我说过我不会为你编写代码......好吧,我做到了:这个小提琴完全符合你的要求。我用上下文(this
)、闭包问题和隐含的全局变量解决了这个问题。它仍然需要做很多工作,但小提琴展示了每个人一直在说的内容:$(this)
不,不能也永远不会指向一个字符串常量,比如"A", or "B"
.
很抱歉这么说,但你的代码充满了问题,但我会在这里解决你问的具体问题。
在循环内部,您分配了一个单击处理程序,基本上如下所示:
function()
{
$('#box2').text(new_info);
}
wherenew_info
是在更高范围内声明的变量。到目前为止,一切都很好。问题是,您正在创建的函数对象没有它自己的任何值的副本,该变量 ( new_info
) 在创建该函数时碰巧持有。相反,该函数引用该变量。因此,当调用这些函数中的任何一个时,$('#box2').text(new_info)
它将被解析为$('#box2').text("whatever value new_info holds when function is called")
,而不是$('#box2').text("whatever value new_info was holding when function was created")
。您只需在代码中添加第二个函数,即可让每个回调访问副本:
$(this).click((function(currentNewInfo)
{
return function()
{
$('#box2').text(currentNewInfo);
}
}(new_info)));
我在这里所做的是创建一个函数,它接受一个参数,并立即调用它。new_info
我作为参数传递,因此 的值currentNewInfo
将是new_info
当时的值(也称为副本)
我调用的函数(IIFE - 或立即调用的函数表达式)返回实际的回调。在这个回调中,我没有引用new_info
,而是 IIFE: 的参数currentNewInfo
。
因为每个函数都有自己的范围,所以该变量是封闭的(因此命名为closure),并且不能从外部访问或更改。唯一仍然可以访问该currentNewInfo
变量的是 IIFE 返回的函数。
也许您担心名称冲突(您创建的每个回调都使用引用currentNewInfo
),但事实并非如此:每个回调都是由单独的函数创建的,因此可以访问不同的范围。不能相互访问的范围之间不可能发生名称冲突......只是为了让事情变得非常容易理解:
Where /\ and /\
|| ||
is return function() is scope of IIFE
所以闭包在函数返回后可以访问函数的作用域。在将表达式解析为值时,该范围具有优先权。为了更好地理解这一点,这里有一个类似的图表来展示JS如何解析表达式:
其中每个粉红色的“外部环境记录”是一个函数的范围(已经返回的函数的闭包范围或当前正在调用的函数)。最后一个环境要么是全局对象,要么是 null(在严格模式下)。这里的所有都是它的。
老实说,一开始闭包很难理解,但是一旦你掌握了我在这里试图解释的内容,它们就会非常有趣。
检查这个链接我可以继续解释嵌套闭包的用例和好处以及工作方式,但我最终会写一本书。我发布的链接很好地解释了封闭是如何使用相当愚蠢的图纸工作的。这可能看起来很幼稚,但当我试图掌握 lambda 函数、闭包和作用域的概念时,它们实际上帮助了我很多,而不是函数调用。上面的图表取自我链接到的页面,它更深入地解释了这些概念,但我仍然认为简单、粗略的绘图是非常自我解释的。
其他问题:
正如有人指出的那样: “您期望this
参考什么”。查看代码片段,this
只会引用全局对象 (window
),如果您问我,将相同/相似的事件处理程序附加到window
根本没有意义。
全局变量是邪恶的,隐含的全局变量更是如此。我看不到new_info
,也没有myArray
在任何地方被宣布。JS 解析表达式的方式有点令人遗憾,并且回退到创建全局变量,而没有太多的窥视:
var bar = 666;//global, always evil
function createGlobal()
{
var local = 2;
foo = bar * local;
}
createGlobal();
让我们看看foo
:
JS is in createGlobal scope: var local is declared, and assigned 2.
foo is used, and assigned bar*local
|| || \\=>found in current scope, resolves to 2
|| ||
|| \\=>found in global scope, resolves to 666
||
||
||=> JS looks for foo declaration in function scope first, not found
||
||=> moves up 1 scope (either higher function, or global scope)
||
\\=>Global scope, foo not found, create foo globally! - hence, implied global
\\
\\=>foo can now be resolved to global variable, value undefined
过多的 DOM 查询:你的事件处理回调看起来像这样:
$('#box2').text(new_info);
这个( $('#box2')
)其实和写一样document.getElementById('#box2')
。这实际上是英语。可以这样想:每次客户端点击$(this)
——无论是什么,你都在访问 DOM,并扫描它以查找具有给定 ID 的元素。为什么不这样做一次并使用保存在内存中的引用来更改文本。这节省了无数的 DOM 查询。你可以使用一个变量,或者(根据我对闭包的解释),一个闭包:
var list = (function(box2, list, i)
{//list & i are arguments, so local to scope, too
for (i = 0; i < myArray.length; i++)
{
list += "<br>" + myArray[i].letter;//<-- don't know why you use this
//new_info = myArray[i].link; no need for this var
$(this).click((function(new_info)
{//new_info is closure var now
return function ()
{//box2 references DOM element, is kept in memory to reduce DOM querying
box2.text(link);
};
}(myArray[i].link));//instead of new_info, just pass value here
}
return list;//return string, assign to outer variable
}($('#box2'), ''));//query dom here, pass reference as argument