闭包和事件监听器导致内存泄漏

2023-12-20 09:23:54
function attachEvent(element, type, handler) {
    if (element.addEventListener) {
        element.addEventListener(type, handler, false);
    } else if (element.attachEvent) {
        element.attachEvent("on" + type, handler);
    } else {
        element["on" + type] = handler;
    }
}

function addLoadHandler(handler) {
    attachEvent(window, "load", handler);
}

function init() {
    var divs = document.getElementsByTagName("div");
    for (var i = 0; i < divs.length; i++) {
        divs[i].onclick = function(event) {
            alert(this.id); // 显示点击的div元素的id
        };
    }

    addLoadHandler(function() {
        console.log("Page loaded");
    });
}

init();

在这个例子中,我们首先定义了一个名为 attachEvent 的函数,用于向DOM元素添加事件监听器。然后我们定义了一个名为 addLoadHandler 的函数,用于向窗口添加一个“load”事件处理器。

init 函数中,我们获取了所有 <div> 元素,并为每个元素添加了一个点击事件处理器。当用户点击一个 <div> 元素时,会弹出一个警告框显示该元素的ID。

此外,我们还使用 addLoadHandler 函数向窗口添加了一个 “load” 事件处理器,当页面加载完成后会在控制台打印一条消息。

虽然这段代码看起来没什么问题,但它实际上会导致内存泄漏。原因是每个 <div> 元素都有一个指向匿名函数的引用,而这个匿名函数又有一个指向包含它的 init 函数作用域的闭包。因此,只要这些 <div> 元素存在,它们的事件处理器就不能被垃圾回收机制清除,从而导致内存泄漏。

要解决这个问题,你可以使用命名函数而不是匿名函数作为事件处理器:

function handleDivClick(event) {
    alert(this.id); // 显示点击的div元素的id
}

function init() {
    var divs = document.getElementsByTagName("div");
    for (var i = 0; i < divs.length; i++) {
        divs[i].onclick = handleDivClick;
    }

    addLoadHandler(function() {
        console.log("Page loaded");
    });
}

init();

现在,所有的 <div> 元素都共享同一个函数实例,因此不会出现内存泄漏的问题。

文章来源:https://blog.csdn.net/wangyue4/article/details/135098648
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。