JavaScript中事件中引用的本地函数会发生什么?

6

我认为我在 JavaScript 方面缺少非常重要的东西。

var gl = 10
$(document).ready(function() {
    var obj = {}
    obj.test = function() {
        gl++

        var lc = gl
        function y() {
            alert('local = ' + lc)
        }

        (function() {
            var k = lc + 1
            $('#button').click(function() {
                alert('local anonymous = ' + k)
                y()
            })                  
        })();

    }

    obj.test()
    $('#button').off()
    obj.test()          
})

在上面的场景中,我定义了一个对象'obj'并为该对象创建了一个方法'test'。在该方法内部,我有一个本地函数'y()',它被附加到按钮的'click'事件中使用。同时,点击事件在匿名函数中被附加。
然后我调用了'test()',取消订阅了按钮的'click'事件,并再次调用了'test()'。结果得到了预期的本地变量等于12和本地匿名变量等于13。
但是我不理解JavaScript在内存中的操作,尤其是在每个步骤中对函数'y()'和匿名函数的操作。
我的具体问题如下,但如果您能解释整个流程,我将非常感激。
那么,当我分离了所有引用第一个'obj.test()'的事件时,例如仅'click'事件。在这种情况下,我猜测JavaScript会销毁'obj.test()'范围和所有函数,包括匿名函数的范围。我需要关心其他方面吗?
我的用例:我正在创建动态页面加载,具有不同的页面行为,因此我希望将每个页面的JavaScript分开放置在全局对象方法中,并且一旦加载新页面,我想分离前一页的所有事件并调用行为函数。但是突然间我意识到我真的不了解JavaScript的工作方式,这种方法可能会导致非常严重的内存泄漏。 :--)
非常感谢!

2
这可能对解释这个是如何/为什么起作用有所帮助:JavaScript 闭包 - War10ck
1个回答

3
当你使用.off来解绑点击事件时,lcky()此时可以被浏览器在进行垃圾回收(gc)时释放。在下一行中,当你调用了obj.test(),因此解绑点击事件后,obj在那个时刻将无法被垃圾回收,因为你在解绑事件之后再次运行了它。现在,lcky()在与第一次调用obj.test时的作用域分离开来重新定义,原始的变量现在可以被gc释放,但是新定义的变量则不能被释放。如果稍后解除点击事件的绑定,则lcky()obj将不再被任何内容引用,因此可以被gc释放。
以上有点令人困惑,我将尝试让它更清晰。
只要obj内部的某些东西引用了由obj.test()创建的作用域上方的某些东西,obj就不会被垃圾回收。由于调用obj.test()而绑定事件处理程序会引用obj.test()作用域内的变量,而元素是dom的一部分,因此直到事件不再绑定到元素上,obj才能被垃圾回收。
以下是一个示例:
(function(){
    var a = 1;
    function doA() {
        a++;
    }
    $("#myEl").click(doA);
})();

只要#myEl上存在点击事件,adoA就无法被垃圾回收。

谢谢你的回答。现在很清楚了!您个人对于动态页面加载有什么建议:是有一个 JavaScript 文件并提前为所有页面(比如说20页针对移动设备简单问答游戏)注册所有事件,还是取消前一个页面的所有事件并订阅当前页面的事件(不确定实践中是否安全)? - potomok
这取决于页面的内容。听起来你正在做的事情实际上可以使用相同的事件处理所有页面。 - Kevin B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接