为什么全局声明的let变量无法在new Function中访问而var可以?
问题核心原因
这一差异本质是两个JS语法规则共同作用的结果:
1. new Function的作用域绑定规则
所有通过new Function构造函数创建的函数,不会和创建时的外层作用域形成闭包,它们的执行上下文永远绑定全局作用域。也就是说这类函数运行时,只能访问两类变量:
- 函数自身内部声明的局部变量
- 全局作用域下的变量
无法访问创建new Function时所在的外层局部作用域、模块作用域内的变量。
2. 不同全局声明的存储差异
同样是写在全局脚本最外层的变量,不同声明方式的存储位置不同:
- 用
var声明的全局变量、不写关键字直接赋值生成的隐式全局变量:会自动挂载到**全局对象(浏览器为window,Node.js为globalThis)**上,属于全局作用域可直接访问的变量。 - 用
let、const、class声明的全局变量:不会挂载到全局对象上,而是存储在全局作用域的词法环境记录中,本身仍然属于全局变量,正常情况下可以被全局作用域下运行的代码访问。
触发报错的常见场景
如果你确实把let value写在普通非模块脚本的最外层,new Function是可以正常访问到的,你遇到报错的最可能原因是运行代码的环境不是全局作用域:
场景1:代码运行在ES模块中
如果你的代码是放在<script type="module">标签里,或是Node.js的ES模块文件中,那么文件最外层的作用域不是全局作用域,是模块私有作用域:
- 你在顶层写的
let value = "test"只是模块内部的私有变量,不属于全局变量 new Function创建的函数绑定全局作用域,自然找不到只存在于模块作用域的value
如果你测试时var可以正常输出,大概率是测试var时用了普通非模块脚本,测试let时切换到了模块环境。
场景2:let value实际声明在局部作用域中
如果你是把let value = "test"写在了某个回调函数(比如window.onload、DOM事件回调)、自定义函数的内部,那么它只是该函数的局部变量,不属于全局变量,new Function自然无法访问。
而如果你此时用value = "test"不写关键字赋值,会自动生成隐式全局变量,挂载到全局对象上,所以new Function可以访问到。
验证&解决方案
你可以加一行打印确认value的作用域归属:
let value = "test"; console.log(window.value); // 普通全局脚本输出undefined,模块/局部作用域输出undefined,var声明的全局变量输出'test' function getFunc() { let func = new Function('console.log(value)'); return func; } getFunc()();
如果要在模块/局部作用域下让new Function可以访问到value,可以手动把它挂载到全局对象上:
let value = "test"; window.value = value; // 手动挂载到全局对象 function getFunc() { let func = new Function('console.log(value)'); return func; } getFunc()(); // 正常输出test
内容的提问来源于stack exchange,提问作者Anonymous
相关产品推荐
相关产品推荐

