如何解决JavaScript 程序如何知道 ECMA-262 是否定义了全局属性名称?
考虑一个名为 isEcmaGlobal
的假设函数,它为 ECMA-262 全局变量的字符串名称返回 true
。
$ node
> isEcmaGlobal('Array')
true
> isEcmaGlobal('process')
false
如何设计这个功能?
解决方法
这里要小心。在这个答案有意义之前,我们需要问另一个问题:我们是按照 ECMA-262(“标准”)现在的规定对全局变量进行分类,还是按照管理我们程序运行时的标准?
换句话说:多台机器应该看到相同的答案吗?
按照现行标准
假设我们希望 isEcmaGlobal
返回 true
就标准所说的现在。我不会在这里展示任何代码,因为如果您关心此类问题,那么您可能已经考虑过下载或抓取标准全局名称。
按照当前运行时
现在假设我们希望 isEcmaGlobal
根据当前运行时中可用的离线信息返回 true
。这并不像遍历全局对象的“自己的”属性名称并根据硬编码数组(如 ['Array','Object',...]
)检查它们那么容易。如果我们这样做了,那么我们就必须验证我们的数组是否正确。我们无法验证硬编码数据,因为它假定 isEcmaGlobal
已经为那个确切的运行时间编写了!我们无法粘贴 ECMA-262 中的全局名称,因为我们不知道该文档的版本是否与运行时相同。我们也无法检查互联网,因为我们假设了一个离线解决方案。
所以我们不能硬编码,但我们可以尝试其他的东西。我将使用 Node.js v14.16.0 及其内置的 vm
模块。该程序利用 vm
在新评估器中提供标准全局变量的需要。我们告诉 vm
使用空的全局对象评估代码,但该全局对象不会为空。
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')())
扔进去,我们就可以回家了。
但是我们正在做一个谓词,所以假设“精益”全局对象是正确的,评估将抛出一个 ReferenceError
非标准标识符。
不幸的是,有些事情是不对的。
> isEcmaGlobal('Array')
true
> isEcmaGlobal('process')
false // yes!
> isEcmaGlobal('global')
false // yes!!
> isEcmaGlobal('console')
true // no!!!
该死,出于某种原因,我们仍然有一个 Node 全局变量。所以在这一点上你可以说我把这一切都变得太复杂了,因为 Node.js 没有添加那么多全局变量,或者我错过了一个配置选项或现有的谓词。你在所有方面都是对的,但这错过了问题的重点。问题以“JavaScript 程序 能知道……吗?”开头,我使用 Node 是为了说明一种解决问题的方法,无需硬编码标准全局名称并产生矛盾。即使 Node.js 只添加了一个非标准的全局变量,如果我们不能得到一个干净的评估器,问题仍然存在。
回顾
要在 某些 JavaScript 运行时中实现 isEcmaGlobal
,该运行时需要为您提供一种方法来运行 bare-bones JS 评估器,无需任何主机- 特定的扩展。 eval
不算。使其只接受标识符,然后评估这些标识符。将异常解释为返回 false
的原因。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。