javascript – 如何使这个代码工作?
代码给我:A B C
当我点击美国广播公司总是显示我最后一个“伏特加”。 我想要“martin”(对于A),“lindsay”(对于B),“伏特加”(对于C)
请帮我看看我的例子。
myArray = [ { letter: "A", brand: "martin" }, { letter: "B", brand: "lindsay" }, { letter: "C", brand: "vodka" } ]; var list = ''; for (var i = 0; i < myArray.length; i++) { list += "<br>" + myArray[i].letter; new_info = myArray[i].link; (function(new_info) { $(this).click(function(){ //this - refers to A or B or C $('#box2').text(new_info); }); }).call(this, myArray[i]) } $('#box1').append(list);
编辑:
我说我不会为你编写代码…呃,我做了: 这个小提琴正是你要找的东西。 我解决了上下文( this
)的问题,closures问题和隐含的全局variables。 它仍然需要很多的工作,但小提琴显示每个人都说过: $(this)
不,不会,也不会指向像"A", or "B"
的string常量 。
对不起,这样说,但是你的代码充满了问题,但我会解决你在这里问的具体问题。
在循环内部,你正在分配一个点击处理程序,基本上是这样的:
function() { $('#box2').text(new_info); }
其中new_info
是一个在更高范围内声明的variables。 到现在为止还挺好。 问题是,你正在创build的函数对象没有自己的副本 ,该函数创build时variables( new_info
)碰巧保存的任何值。 相反,该函数引用该variables。 所以当这些函数被调用时, $('#box2').text(new_info)
将被parsing为$('#box2').text("whatever value new_info holds when function is called")
,而不是$('#box2').text("whatever value new_info was holding when function was created")
。 您可以通过简单地在代码中添加第二个函数来为每个callback提供访问权限:
$(this).click((function(currentNewInfo) { return function() { $('#box2').text(currentNewInfo); } }(new_info)));
我在这里做的是创build一个函数,它需要一个参数,并立即调用它。 我将new_info
作为parameter passing,所以currentNewInfo
的值将成为当时的new_info
(又名副本)
我调用的函数(IIFE – 或立即调用的函数expression式)返回实际的callback。 在这个callback中,我没有引用new_info
,而是引用了IIFE: currentNewInfo
。
由于每个函数都有自己的作用域,所以这个variables是封闭的 (因此名称closures ),并且不能从外部访问或修改。 唯一可以访问currentNewInfo
variables的是IIFE返回的函数。
也许你担心名称冲突(你创build的每个callback都使用引用currentNewInfo
),但事实并非如此:每个callback都是由一个单独的函数创build的,因此可以访问不同的范围。 在彼此不访问的范围之间不可能有名字冲突…只是为了使事情变得简单易懂:
Where /\ and /\ || || is return function() is scope of IIFE
因此,闭包在返回后可以访问函数的作用域。 当涉及到将expression式parsing为值时,该范围具有优先权。 为了更好地理解这一点,下面是一个类似的图来展示JS 如何parsingexpression式:
其中每个粉红色的“外部环境logging”是一个函数的范围(已经返回的函数的闭包范围或当前被调用的函数)。 最后一个环境将是全局对象,或者是null(严格模式)。 这就是它的全部。
老实说,closures起来很麻烦,所以一旦你掌握了我想在这里解释的东西,他们就非常有趣。
检查这个链接,我可以继续解释用例和好处,以及嵌套闭包的工作方式,但是我最终会写一本书。 我发布的链接很好地解释了如何使用相当愚蠢的图纸closures工作。 这看起来可能是幼稚的,但是当我试图把握lambda函数,闭包和范围外的概念时,他们实际上帮了我很大的忙。 上面的图表取自我链接的页面,这更深入地解释了这些概念,但我仍然认为简单粗糙的graphics非常自我解释。
其他事宜:
正如有人指出: “你期待this
参考” 。 看一下这个代码片段,只要引用全局对象( window
),将相同的/相似的事件处理程序附加到window
上,如果你问我,就没有任何意义。
全局variables是邪恶的 , 隐含的全局variables更是如此。 我看不到new_info
,也没有声明myArray
在任何地方。 JS解决expression式的方式有点不幸,而且又回到了创build全局variables的问题上,而没有像窥视一样:
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查询:您的事件处理程序callback都如下所示:
$('#box2').text(new_info);
这( $('#box2')
)实际上和写document.getElementById('#box2')
。 这实际上是英语。 这样想一下:客户端每次点击$(this)
– 无论如何,您正在访问DOM,并扫描具有给定ID的元素。 为什么不这样做一次,并使用内存中的引用来改变文本。 这节省了无数的DOM查询。你可以使用一个variables,或者(根据我所解释的closures),一个闭包:
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