[英]How can a JavaScript program know if a global property name was defined by ECMA-262?
考虑一个名为isEcmaGlobal
的假设 function,它对 ECMA-262 全局变量的字符串名称返回true
。
$ node
> isEcmaGlobal('Array')
true
> isEcmaGlobal('process')
false
如何设计这个 function?
让我们在这里小心。 在这个答案有意义之前,我们需要问另一个问题:我们是按照 ECMA-262(“标准”)现在所说的,还是按照管理程序运行时的标准对全局变量进行分类?
换句话说:多台机器应该看到相同的答案吗?
假设我们希望isEcmaGlobal
根据标准现在所说的返回true
。 我不会在这里显示任何代码,因为如果您关心此类问题,那么您可能已经考虑过下载或抓取标准全局名称。
现在假设我们希望isEcmaGlobal
根据当前运行时中可用的离线信息返回true
。 这不像迭代全局 object 的“自己的”属性名称并对照硬编码数组(如['Array', 'Object', ...]
检查它们那么容易。 如果我们这样做了,那么我们必须验证我们的数组是否正确。 我们无法验证硬编码数据,因为它假定isEcmaGlobal
已经为该确切运行时编写,我们无法粘贴来自 ECMA-262 的全局名称。 因为我们不知道该文档的版本是否与运行时相同。 我们也无法检查互联网,因为我们假设了离线解决方案。
所以我们不能硬编码,但我们可以尝试别的东西。 我将使用 Node.js v14.16.0 及其内置的vm
模块。 该程序利用了vm
在新评估器中提供标准全局变量的需要。 我们告诉vm
使用空的全局 object 来评估代码,但是全局 object 根本不会为空。
const vm = require('vm');
function isEcmaGlobal(identifier) {
try {
// Lol, what security?
vm.runInContext(identifier, vm.createContext({}))
return true;
} catch (e) {
return false;
}
}
这里有几件事。
首先,警告:此示例使用未经处理的代码执行来说明和简洁。 不要将其放在剪贴板上以采取捷径。
其次,您可以看到我们的目标是创建一个新的评估器,只定义标准的全局变量,并且看不到评估器之外发生的事情( eval
不会做这些事情中的任何一个)。 如果我们得到了那个评估器,那么你可以把Object.getOwnPropertyNames(new Function('return this')())
扔进去,我们就都回家了。
但是我们正在做一个谓词,所以假设“精简”全局 object 是正确的,评估将为非标准标识符抛出一个ReferenceError
。
不幸的是,有些事情是不对的。
> isEcmaGlobal('Array')
true
> isEcmaGlobal('process')
false // yes!
> isEcmaGlobal('global')
false // yes!!
> isEcmaGlobal('console')
true // no!!!
该死,由于某种原因,我们仍然有一个全局节点。 所以在这一点上,你可能会说我让这一切变得太复杂了,因为 Node.js 没有添加那么多 globals ,或者我错过了配置选项或现有谓词。 你在所有方面都是对的,但这没有抓住问题的重点。 问题以“ JavaScript 程序是否知道...?”开头,我使用 Node 旨在说明一种解决问题的方法,而无需硬编码标准全局名称并产生矛盾。 即使 Node.js 只添加了一个非标准全局,如果我们无法获得一个干净的评估器,问题仍然存在。
要在某些JavaScript运行时中实现isEcmaGlobal
,该运行时需要为您提供一种运行基本 JS 评估器的方法,无需所有特定于主机的扩展。 eval
不算。 使您只接受标识符,然后评估这些标识符。 将异常解释为返回false
的原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.