You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何内存快照中onevent属性会被当作闭包处理?

问题

触发largeClosures()和stopAndClear()点击事件后,我用Microsoft Edge开发者工具的Memory面板获取内存快照,发现这两个事件处理器被归类到(closure)条目下,每个占用32字节内存。这些事件是通过HTML的onevent属性(比如onclick)绑定到DOM元素的,按传统理解,闭包应该是像lC、sC、eC这类捕获了外层函数局部变量的函数,为什么这两个事件处理器会被标记为闭包?

示例代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <p>Analyze the impact of closures on memory</p>
  <p>
    <button onclick="largeClosures()">
      Closures maintain hold on large string
    </button>
  </p>
  <p>
    <button onclick="smallClosures()">
      Closures maintain hold only on small strings
    </button>
  </p>
  <p>
    <button onclick="evalClosures()">Closures with <code>eval</code></button>
  </p>
  <button onclick="stopAndClear()">Stop and clear</button>
  <script>
    var closures = [];

    function createLargeClosure() {
      var largeStr = new Array(1000000).join("x");
      return function lC() {
        return largeStr;
      };
    }

    function createSmallClosure() {
      var smallStr = "x";
      var largeStr = new Array(1000000).join("x");
      return function sC() {
        return smallStr;
      };
    }

    function createEvalClosure() {
      var smallStr = "x";
      var largeStr = new Array(1000000).join("x");
      return function eC() {
        eval("");
        return smallStr;
      };
    }

    function largeClosures() {
      closures.push(createLargeClosure());
    }

    function smallClosures() {
      closures.push(createSmallClosure());
    }

    function evalClosures() {
      closures.push(createEvalClosure());
    }

    function clear() {
      closures.length = 0;
    }

    function stopAndClear() {
      clear();
    }
  </script>
</body>

</html>

内存快照截图

Edge开发者工具Memory面板的内存快照,显示(closure)条目包含largeClosures和stopAndClear事件处理器

原因解释

当你通过HTML的onclick这类onevent属性绑定事件时,浏览器并不会直接把你指定的函数(比如largeClosures)绑定到元素上,而是会自动生成一个包装函数,逻辑类似:

function(event) {
  largeClosures();
}

这个包装函数需要访问全局作用域中的largeClosures函数,因此它会捕获并持有对全局作用域的引用——这完全符合闭包的定义:一个函数能够访问其词法作用域之外的变量,即使在该作用域之外执行。

开发者工具会把这类捕获了外部作用域的包装函数标记为闭包,和你例子中lC、sC这类捕获外层函数局部变量的典型闭包本质一致,只是它们捕获的作用域层级不同(一个是全局作用域,一个是函数局部作用域)。

另外,哪怕你用JS代码手动绑定类似的匿名函数(比如button.onclick = () => largeClosures()),这个匿名函数同样会被标记为闭包,因为它也需要访问全局作用域的largeClosures。

内容的提问来源于stack exchange,提问作者Lin Du

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 21:55:56