我需要在 DOM 事件回调中使用闭包吗?

发布于 2025-01-07 09:58:41 字数 1608 浏览 0 评论 0原文

我正在尝试构建一个类似 jQuery.live 的函数。 Helper 是一个具有 _liveEvent_addEventListener 方法的类。 Helper._addEventListener 只是 W3C addEventListener 的跨浏览器版本。

Helper.prototype._liveEvent = function(type, evt, ofunc) {
    var elHand = document;
    type = type.toUpperCase();

    this._addEventListener(elHand, evt, function(me) {
        // Inside here I use the `type` variable.
        // I don't know why but it works.

        for (var el = me.srcElement; el.nodeName !== 'HTML';
            el = el.parentNode)
        {
            if (el.nodeName === type || el.parentNode === null) {
                break;
            }
        }
        if (el && el.nodeName === type) {
            ofunc.call(el, me);
        }

    });
};

我使用不同的类型运行 Helper._liveEvent 函数两次,它工作得很好。我认为由于 type 变量是在 _liveEvent 上下文中设置的,因此 _addEventListener 回调只能看到该变量的最后一个版本。但事实并非如此,它似乎工作得很好。

我的问题是:

  • 为什么 _addEventListener 回调可以看到该类型的两个版本?
  • 这是否意味着我的代码正在泄漏内存?

更新

另一个例子让我更好地理解了这一点,但我不确定我是否完全理解它。

function foo(i) {
    setTimeout(function() {
        console.log(i);
    }, 400);

}

// Prints 1, 2, 3
for (var i = 1; i < 4; i++) {
    foo(i);
}

function bar() {
    for (var i = 1; i < 4; i++) {
        setTimeout(function() {
            console.log(i);
        }, 400);
    }
}

// Prints 4, 4, 4
bar();
​

I'm trying to build a jQuery.live like function.
Helper is a class that has the _liveEvent and _addEventListener methods. Helper._addEventListener is just a CrossBrowser version of W3C addEventListener.

Helper.prototype._liveEvent = function(type, evt, ofunc) {
    var elHand = document;
    type = type.toUpperCase();

    this._addEventListener(elHand, evt, function(me) {
        // Inside here I use the `type` variable.
        // I don't know why but it works.

        for (var el = me.srcElement; el.nodeName !== 'HTML';
            el = el.parentNode)
        {
            if (el.nodeName === type || el.parentNode === null) {
                break;
            }
        }
        if (el && el.nodeName === type) {
            ofunc.call(el, me);
        }

    });
};

I'm running the Helper._liveEvent function twice with different types, and it works just fine. I thought that since the type variable was set inside the _liveEvent context the _addEventListener callback could see only the last version of that variable. But it's not the case, it seems to be working fine.

My questions are:

  • Why the _addEventListener callback can see both versions of the type?
  • Does it mean my code is leaking memory?

UPDATE

This other example made me understand this better, but I'm not sure I understand it fully yet.

function foo(i) {
    setTimeout(function() {
        console.log(i);
    }, 400);

}

// Prints 1, 2, 3
for (var i = 1; i < 4; i++) {
    foo(i);
}

function bar() {
    for (var i = 1; i < 4; i++) {
        setTimeout(function() {
            console.log(i);
        }, 400);
    }
}

// Prints 4, 4, 4
bar();
​

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

山人契 2025-01-14 09:58:41
  • 这是因为为传递给 _addEventListener() 的匿名函数的每个实例创建了一个单独的闭包作用域,每个实例都有自己的 elHandtype 值>。
  • 这取决于你所说的“泄漏”是什么意思。每个闭包都会阻止它包含的对象被 GC 处理。当没有更多对象(例如,像您这样的匿名函数)引用闭包时,它就会被 GC 回收。从这个意义上说,是的,您存在内存泄漏,因为您无法删除添加的侦听器(匿名函数),从而使关联的作用域对象符合 GC 的条件。
  • It's because a separate closure scope is created for every instance of the anonymous function passed to _addEventListener(), each having its own values of elHand and type.
  • It depends on what you mean by "leaking". Every closure prevents objects that it contains from GC'ing. A closure is GC'ed when there are no more objects (say, anonymous functions like yours) referencing it. In this sense, yes, you have a memory leak, as you have no way to remove the added listener (anonymous function) thereby making the associated scope object eligible for GC.
手心的温暖 2025-01-14 09:58:41

实际上,您已经在创建一个闭包。这就是为什么:

for( var i=0; i<10; i++) {
    elem.onclick = (function(id) {alert(id);})(i);
}

有效 - 调用匿名函数创建一个新的闭包,并将 id 设置为 i当前值。 (我个人喜欢将参数称为与我要使用的变量相同的东西,因此我可以将其视为“锁定”该函数的变量值)。

就内存泄漏而言,两次调用不会导致泄漏。如果 GC 按我认为的方式工作,它会删除任何没有指向它们的闭包。特别是,当您离开某个页面时,与该页面关联的所有内存都会被释放。

Effectively, you already are creating a closure. This is why:

for( var i=0; i<10; i++) {
    elem.onclick = (function(id) {alert(id);})(i);
}

works - calling the anonymous function creates a new closure with id set to the current value of i. (Personally I like to call the argument the same thing as the variable I want to use, so I can think of it as "locking" the value of the variable for that function).

As far as memory leaks go, two calls is not going to cause a leak. If GC works the way I think it does, it removes any closures that have no pointers to them. In particular, when you leave a page, any memory associated with that page is freed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文