javascript - 如何使此代码工作?

IT技术 javascript jquery closures
2021-02-12 19:33:00

代码给了我: A B C

当我点击 ABC 时,它总是向我显示最后一种“伏特加”。我想要“马丁”(A)、“林赛”(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);
1个回答

编辑:
我说过我不会为你编写代码......好吧,我做到了:这个小提琴正是你正在寻找的。我用上下文 ( 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作为参数传递,所以currentNewInfowill的值是当时new_info持有的(又名副本)
我调用的函数(IIFE - 或立即调用的函数表达式)返回实际的回调。在这个回调中,我不引用new_info,而是引用IIFE: 的参数currentNewInfo

因为每个函数都有自己的作用域,所以该变量是封闭的(因此命名为closure),并且不能从外部访问或更改。唯一仍然可以访问该currentNewInfo变量的是 IIFE 返回的函数。
也许您担心名称冲突(您创建的每个回调都使用引用currentNewInfo),但事实并非如此:每个回调都是由一个单独的函数创建的,因此可以访问不同的范围。在不相互访问的范围之间不可能有名称冲突......只是为了让事情变得非常容易理解:

闭包有什么作用

Where  /\            and      /\
       ||                     ||
  is return function()      is scope of IIFE

所以闭包可以在函数返回后访问它的作用域。在将表达式解析为值时,该范围具有优先权。为了更好地理解这一点,这里有一个类似的图表向您展示JS如何解析表达式:

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
对一个可怕问题的出色回答... +1
2021-03-20 19:33:00
你能不能修改我的代码。这是我关闭的最好方法。我没有通过阅读其他示例(我已经尝试过)来理解它。谢谢。
2021-03-20 19:33:00
@BenDelton:您现在可能使用闭包的代码,但很遗憾地说您不明白,直到您可以自己创建/使用它们。我已经编辑了您的代码段,解决了最明显的问题(全局变量、过多的 DOM 查询和没有自己独特行为的回调),但我无法解决这个问题this,因为我不知道您想this参考什么
2021-03-24 19:33:00
@门把手:谢谢。我可能很天真,但老实说,我相信即使是最明显的问题也可以为人们服务,如果你在答案上付出一些努力......我只希望 OP 也有同样的感觉:P
2021-03-30 19:33:00
“this”指的是“字母”,点击时A或B或B。希望能帮助到你。如果你对闭包了解这么多,你可以帮我写代码。谢谢
2021-04-13 19:33:00