为什么一旦代码被提取到一个单独的函数中,循环内的javascript代码就可以工作?

为什么一旦代码被提取到一个单独的函数中,循环内的javascript代码就可以工作?,javascript,jquery,Javascript,Jquery,我在一个jQuery插件中编写了以下代码,用于创建标记云。我正在以[{tag:“028”,count:15},{tag:“101”,count:357}的格式传入一个数据数组。我现在正在创建云作为跨度,根据计数标准化大小。正确创建跨距,即跨距具有正确的大小和文字。我添加了两个事件,单击和鼠标事件。无论单击哪个范围,它总是向我显示数组中最后一个元素的警报 在调试过程中,我将元素创建代码提取到一个单独的函数中。一旦我这样做了,点击事件就正常工作了,即点击事件显示了所点击跨度的正确数据 我假设两个版本

我在一个jQuery插件中编写了以下代码,用于创建标记云。我正在以[{tag:“028”,count:15},{tag:“101”,count:357}的格式传入一个数据数组。我现在正在创建云作为跨度,根据计数标准化大小。正确创建跨距,即跨距具有正确的大小和文字。我添加了两个事件,单击和鼠标事件。无论单击哪个范围,它总是向我显示数组中最后一个元素的警报

在调试过程中,我将元素创建代码提取到一个单独的函数中。一旦我这样做了,点击事件就正常工作了,即点击事件显示了所点击跨度的正确数据

我假设两个版本会产生相同的结果。为什么一旦我将元素创建提取到它自己的函数中,单击事件就会起作用

这是不起作用的版本:

for (var i = 0; i < tagList.length; ++i) {
    if (tagList[i] != null) {
        var tagValue = tagList[i].tag;
        var tagCount = tagList[i].count;
        var size = getNormalizedSize(tagCount);
        var theSpan = getText(tagValue, tagCount);   // <span style="font-size: {1}em">{0}<\/span>
        var theAlert = getAlert(tagValue, tagCount); // "Project {0} is has logged in {1} drawings"
        var newElement = $(theSpan);
        newElement.click(function() {
            alert(theAlert);                        // Always shows data from last element in array
        }).mouseenter(function(event) {
            $(this).css('backgroundColor', '#FFC');
        }).mouseleave(function() {
            $(this).css('backgroundColor', '#FFF');
        });
        this.append(newElement).append(" ");
    }
}
for(变量i=0;i
这是有效的版本:

for (var i = 0; i < tagList.length; ++i) {
    if (tagList[i] != null) {
        var tagValue = tagList[i].tag;
        var tagCount = tagList[i].count;
        var tagElem = buildElement(tagValue, tagCount);
        this.append(tagElem).append(" ");
    }
}

function buildElement(tagValue, tagCount) {
    var size = getNormalizedSize(tagCount);
    var theSpan = getText(tagValue, tagCount);   // <span style="font-size: {1}em">{0}<\/span>
    var theAlert = getAlert(tagValue, tagCount); // "Project {0} is has logged in {1} drawings"
    var newElement = $(theSpan);
    newElement.click(function() {
        alert(theAlert);
    }).mouseenter(function(event) {
        $(this).css('backgroundColor', '#FFC');
    }).mouseleave(function() {
        $(this).css('backgroundColor', '#FFF');
    });
    return newElement;
}
for(变量i=0;i
您正在每个处理程序中捕获相同的变量,作用域为循环。然后,当调用处理程序时,它包含分配给它的最后一个值。当您将其移动到函数时,变量的作用域被限定为函数调用的实例,因此循环的每次迭代都不同,并且在迭代期间分配了值。

这是因为两种解决方案具有不同的作用域规则。在第一个函数中没有函数调用,这意味着
theAlert
只定义一次,您只需更新
click
回调处理程序引用的引用。在第二个示例中,您通过调用
buildElement
创建了一个新的作用域,在本例中,这意味着为列表中的每个标记定义了
theAlert
,并且仅在定义后更新,因此每个
单击
闭包引用不同的变量

这里的关键是闭包内的变量(例如,
click
callback)在运行之前不会解析。下面是一个简单的示例,说明了这一点:

var name = 'John';
setTimeout(function(){ alert(name); }, 1000);
name = 'Joe';

因此,即使引用
名称的闭包是在值更改之前创建的,但它实际上要到稍后才会运行,因此将发出警报的名称是“Joe”而不是“John”。

谢谢,我丢失了该键。每天学习新的东西,尤其是在这个网站上。