繁体   English   中英

JavaScript 程序如何知道全局属性名称是否由 ECMA-262 定义?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM