Javascript 闭包保留整个父词法环境还是仅保留闭包引用的值的子集? [复制]

2024-04-18

考虑以下示例:

function makeFunction() {
  let x = 3;
  let s = "giant string, 100 MB in size";

  return () => { console.log(x); };
}

// Are both x and s held in memory here
// or only x, because only x was referred to by the closure returned
// from makeFunction?
let made = makeFunction();

// Suppose there are no further usages of makeFunction after this point

// Let's assume there's a thorough GC run here

// Is s from makeFunction still around here, even though made doesn't use it?
made();

因此,如果我仅关闭父词法环境中的一个变量,那么该变量是否保留,或者其词法环境中的每个同级变量也保留?

另外,如果 makeFunction 本身嵌套在另一个外部函数中,即使 makeFunction 和 makeFunction 的返回值都没有引用该外部词法环境中的任何内容,该外部词法环境是否会被保留?

我问的是性能原因 - 闭包保留了一堆东西还是只保留了它们直接引用的东西?这会影响内存使用和资源使用(例如打开的连接、句柄等)。

这主要适用于 NodeJS 上下文,但也可以适用于浏览器。


V8 开发者在这里。这有点复杂;-)

简短的答案是:闭包只保留他们需要的东西。

所以在你的例子中,之后makeFunction已运行,引用的字符串s将有资格进行垃圾收集。由于垃圾收集的工作原理,无法预测它何时会被释放; “在下一个垃圾收集周期”。无论makeFunction再次运行并不重要;如果它再次运行,将分配一个新字符串(假设它是动态计算的;如果它是源中的文字,那么它会被缓存)。无论made已经运行或将再次运行也没有关系;重要的是你有一个变量引用它,所以你could(再次)运行它。引擎通常无法预测哪些函数将来会执行或不会执行。

更长的答案是有一些脚注。一方面,正如评论已经指出的那样,如果您的闭包使用eval,那么所有内容都必须保留,因为无论源代码片段是什么eval'ed 可以指任何变量。 (一条评论提到了可能指的是全局变量eval但这不是真的; “全局评估”(又名“间接评估”)存在语义差异:它看不到局部变量。这通常被认为是性能和可调试性方面的优势——但更好的是不使用eval根本没有。)

另一个脚注是,有点不幸的是,跟踪并没有达到应有的细粒度:each闭包将保留什么any关闭需求。我们已经尝试修复这个问题,但事实证明,更细粒度的跟踪会导致更多的内存消耗(用于元数据)和 CPU 消耗(用于完成工作),因此对于实际代码来说通常不值得(尽管它会对人工测试恰恰强调了这种情况)。举个例子:

function makeFunction() {
  let x = 3;
  let s = "giant string, 100 MB in size";
  let short_lived = function() { console.log(s.length); }
  // short_lived();  // Call this or don't, doesn't matter.
  return function long_lived() { console.log(x); };
}

let long_lived = makeFunction();

对于这个修改后的例子,即使long_lived只使用x, short_lived确实使用s(即使它从未被调用过!),并且只有一个存储桶用于“来自makeFunction某些封闭所需要的”,这样桶就可以同时保留两者x and s活。但正如我之前所说:真正的代码很少遇到这个问题,所以这通常不是你需要担心的事情。

边注:

以及资源使用情况(例如打开的连接、句柄等)

作为一个非常笼统的陈述(即,在任何语言或运行时环境中,无论闭包或其他什么),通常建议不要依赖垃圾收集来进行资源管理。我建议在适当的时候手动并显式地释放资源。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Javascript 闭包保留整个父词法环境还是仅保留闭包引用的值的子集? [复制] 的相关文章

  • 服务器重新启动时显示等待页面

    我有一个服务器并为其创建一个 Web 界面 如果用户按下页面上的重新启动按钮 则用户将被重定向到reboot php他应该看到一个旋转 gif 直到服务器再次可访问并且服务器通过 shell 执行重新启动 如果服务器可以访问 那么我需要重定
  • Flot 中轴的逗号分隔数字

    有没有办法让 Flot 使轴编号以逗号分隔 例如 用 1 000 000 代替 1000000 您可以通过使用轴的tickFormatter 属性来做到这一点 xaxis tickFormatter function val axis in
  • 如何在Keystone.js List Map中指定多个字段?

    想知道如何在 Keystone js List Map 中指定多个字段 例如 基于 Keystone 数据模型文档 http keystonejs com docs database http keystonejs com docs dat
  • 如何使错误冒泡,以便可以在同一个 try/catch 块中捕获它们?

    我有一个带有抛出错误的函数的对象 myObj ini function this f f function throw new Error 但我只想捕获创建对象的异常 try var o new myObj catch err alert
  • JS 中的触摸板滚动检测,无库

    我正在制作自己的小型 Javascript 库 可以轻松地将您网站 和我的网站 的默认滚动条替换为自定义滚动条 其中一部分意味着为 BODY 元素提供 overflow hidden 样式来隐藏正常的滚动条 但是 这会阻止除代码中完成的滚动
  • 封装的闭包与类?

    我是 JS 来自 C etc 的新手 我突然想到闭包似乎是比类更简单 更方便的处理封装的方法 这段代码似乎给出了一种处理封装的简单方法 function addProperty o var value o get function retu
  • 从 PHP/Web 应用程序打印多个标签到 Dymo LabelWriter 450 Turbo

    我希望添加使用 Dymo LabelWriter 450 Turbo 打印多个标签的功能 我已经从 Dymo 网站下载了 DYMO Label v 8 SDK dmg 但看不到任何 Javascript Web 相关的 SDK 文件或文档
  • 如何在D3中导入json数据?

    如何在D3中导入json文件 I did d3 json temp json 但是我如何在进一步的代码中访问这个数据集呢 到目前为止我已经尝试过 var data d3 json temp json 但使用 data data 在其余代码中
  • Chrome DevTools 脚本黑盒不起作用

    我正在尝试使用 chrome devtools 的新功能 黑盒脚本 这篇 Chrome Devtools 文章列出了脚本黑盒功能 https developer chrome com devtools docs blackboxing wh
  • TSConfig JSX:React JSX 与 React

    在将 Typescript 与 React 一起使用时 我们必须指定jsx in compilerOptions in tsconfig json file It has preserve react react native react
  • 使用 bitcoinjs-lib 发送比特币

    我正在关注 bitcoinjs 的教程https medium com orweinberger how to create a raw transaction using bitcoinjs lib 1347a502a3a wkf9g2l
  • JS 检查深层对象属性是否存在[重复]

    这个问题在这里已经有答案了 我正在尝试找到一种优雅的方法来检查对象中是否存在某些深层属性 因此 实际上试图避免对未定义的情况进行巨大的保护性检查 例如 if typeof error undefined typeof error respo
  • JavaScript 排序列表

    Javascript 或 jQuery 中有排序列表吗 我有一个巨大的列表 随着时间的推移 插入操作很少 每次添加单个项目时 我无法为整个列表调用 object sort 我需要插入 o log n 不 没有 你拥有的只是Array sor
  • 带条件的 Array.join()

    我该如何使用Array join 有条件的函数 例如 var name aa bb var s name join 输出是 aa bb 我想添加一个条件 仅显示不为空的单词 aa bb 您可以使用Array filter https dev
  • 尝试利用?

    我看到我的 nopCommerce 网站记录了以下搜索 ADw script AD4 alert 202 ADw script AD4 我有点好奇他们想要完成什么 我搜索了一下 似乎是ADw script AD4 以 UTF7 编码为
  • 在画布中的鼠标位置放大/缩小

    我正在尝试使用 p5 js 实现缩放功能 当前缩放级别以及 x 和 y 位置存储在controls view目的 默认位置或 0 0 位置位于左上角 问题是调整放大 缩小时的 x 和 y 位置值 以便无论视图的当前位置是什么 它都会停留在缩
  • 脚本和链接标签的简写 http:// 为 // ?有人以前看过/用过这个吗?

    问题如下 如果您使用 addthis 共享按钮 查看任何网站 一旦您浮动在 addthis 按钮上 并且加载了所有必需的资源 请使用 firebug 或 chrome 检查器查看文档的正文 不是源代码 而是屏幕上的实际文档 对象检查器 你会
  • 反应本机中的“未知命名模块”错误

    我正在使用 React Native 创建一个应用程序 但某些导入会引发标题中的错误 Unknown named module 两个包都会发生这种情况 react native material design and react nativ
  • 为什么我无法访问多个网络调用的结果?

    在我的 Node 应用程序中 我试图获取包裹的运输数据 我需要一种方法来获取 json 数据并将其附加到对象或其他东西 以便我可以将其传递到我的渲染页面 使用 pug 这是我的代码 var test for var i 0 i lt res
  • Google Universal Analytics - 命令被忽略

    我正在使用 Google Universal Analytics 来跟踪页面浏览量 当我导航到具有 Google Analytics 网站实时功能的页面时 我可以看到 因此我的代码一定可以正常工作 然而 Chrome 一直在控制台中显示 I

随机推荐