【问题标题】:Javascript closure scopeJavascript 闭包范围
【发布时间】:2016-03-07 07:12:13
【问题描述】:

我今天在一个前端 Javascript 项目中工作。我会尽量简短地描述问题和解决方案。 我必须在将用户重定向到其他页面的页面上的链接中添加点击处理程序,所以我有 2 个 Javascript 数组 arrayOfRedirectLinkspageLinkElements

var arrayOfRedirectLinks, pageLinkElements;

最初我这样写addEventHandlers函数:

var addEventHandlers = function() {
    var i, link;
    for( var i in arrayOfRedirectLinks) {
        link = arrayOfRedirectLinks[i];
        pageLinkElements[i].addEventListener('click', function(e) {
            e.preventDefault();
            window.location = link;
        });
    }
}

我认为这个解决方案可以完成这项工作,直到......好吧,直到我打开浏览器,单击几个链接并注意到它们都将我重定向到同一个链接(arrayOfRedirectLinks 中的最后一个链接)。

最后我发现我的问题与此处发布的问题相似 Javascript multiple dynamic addEventListener created in for loop - passing parameters not working

确实,那里发布的第一个和第二个解决方案都对我有用

var addEventHandlers = function() {
    var i, link;
    for( var i in arrayOfRedirectLinks) {
        (function(link){
        link = arrayOfRedirectLinks[i];
        pageLinkElements[i].addEventListener('click', function(e) {
            e.preventDefault();
            window.location = link;
        });
        }(link));
    }
}

var passLink = function(link) {
    return  function(e) {
               e.preventDefault();
               window.location = link;
            };
};
var addEventHandlers = function() {
    var i, link;
    for( var i in arrayOfRedirectLinks) {
        link = arrayOfRedirectLinks[i];
        pageLinkElements[i].addEventListener('click',passLink(link));
    }
}

现在这似乎有效,但我不明白为什么有效。 我带来了以下解释,我想知道是否有人可以确认它是否正确:

  1. 当我在 Javascript 中声明一个函数时,它会获取对声明它的函数范围内的变量的引用。 (即我的事件处理程序在addEventHandlers 函数中获得对link 变量的引用)

  2. 因为处理程序获得了对变量link 的引用。当我为link 变量重新分配一个值时,点击处理程序被触发时将使用的值也会发生变化。因此,来自事件处理程序的link 变量不仅仅是与link 的复制,具有与添加函数处理程序时不同的内存地址和相同的值,而是它们都共享相同的内存地址,因此具有相同的值。

  3. 1234563在for 循环结束时分配给link 变量。 1234563传递给函数。 2个link变量的引用不同。
  4. 由于 4),当我将 link 传递给单击处理程序时,它将引用立即调用函数表达式中的 link 变量,该变量本身不与link 函数中的 addEventHandlers。因此,事件处理函数中的每个link 都将与其他函数隔离,并将保留arrayOfRedirectLinks[i] 的值

这是正确的吗?

【问题讨论】:

标签: javascript function scope closures dom-events


【解决方案1】:

这是关键:

var i, link;
for( var i in arrayOfRedirectLinks) {
  link = arrayOfRedirectLinks[i];
  pageLinkElements[i].addEventListener('click', function(e) {
    e.preventDefault();
    window.location = link;
  });
}

这里只有一个link 变量。注意addEventListener回调函数只有在点击链接时才会被调用。

到那时,变量link 有它的最终值,它被所有事件处理函数共享。

所以所有的链接都做同样的事情。

最简单的解决方案(除了更广泛的重构):

for(var i in arrayOfRedirectLinks) {      
  (function(i) {
    var link = arrayOfRedirectLinks[i];
    pageLinkElements[i].addEventListener('click', function(e) {
      e.preventDefault();
      window.location = link;
    });
  }(i));
}

【讨论】:

  • 你可以通过处理程序来解耦一点:pageLinkElements[i].addEventListener('click', passLink(link));
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-20
  • 2013-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-26
  • 2013-01-23
相关资源
最近更新 更多