如何在不使用with语句的情况下将对象getter暴露为独立变量
说明: 本问题与常规JavaScript或最佳实践无关,而是作为DSL(领域特定语言)开发的一部分,对JavaScript进行“hack”操作。我正在对该DSL进行向后兼容的更新,需完全匹配现有行为,请在此背景下理解本问题。
问题
假设我们有一个带有getter的对象如下:
let obj = { get foo() { console.log('executed'); return 1; } };
我们的任务是将foo从obj中“提取”出来,这样无需编写obj.foo,直接写foo即可。
使用with语句可以实现此需求:
<script> with(obj) { // 无法控制的用户代码示例: console.log(foo + 1); // 先输出'executed',再输出'2' let bar = 3; // `bar`被限制在with块作用域内,这是我要避免的问题 } </script>
但这样会创建块作用域,导致let bar = 3;这类变量声明被限制在块内,这是我希望避免的。
重要提示:我完全控制上述代码的构造过程,仅会收到用户代码(如上述两行)的字符串形式,可对其进行任意处理,只要能暴露obj的getter,且确保let bar = 3这类顶层声明不被“限制”即可。现有解决方案是解析用户代码中的顶层声明并手动将其移出with块,但我希望彻底移除with语句。
思考
我认为若不使用一些重量级手段(如运行时AST解析),这可能无法实现。with将getter暴露为直接变量名的能力似乎是独一无二的。我在此提问,希望有资深JavaScript开发者知晓我不知道的“黑魔法”。
我认为Proxy在此无用,因为没有针对直接引用Proxy对象本身的处理器,仅能处理其属性或函数调用等操作。
我不确定以下内容与本问题的相关性,因为我不太理解其中细节:
with语句会为计算所得的对象添加一个对象*环境记录(Environment Record)*到运行执行上下文的词法环境中,然后使用该增强的词法环境执行语句,最后恢复原始词法环境。
本规范中使用的环境记录值主要有两种:声明式环境记录和对象式环境记录。声明式环境记录用于定义ECMAScript语法元素(如FunctionDeclarations、VariableDeclarations和Catch子句)的效果,这些元素直接将标识符绑定与ECMAScript语言值关联。对象式环境记录用于定义ECMAScript元素(如WithStatement)的效果,这些元素将标识符绑定与某个对象的属性关联。全局环境记录和函数环境记录是专门用于脚本全局声明和函数内顶层声明的特殊类型。
我目前唯一的替代方案是想出一种可靠的“导出”方式。
内容的提问来源于stack exchange,提问作者joe

