简体   繁体   English

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

[英]How can a JavaScript program know if a global property name was defined by ECMA-262?

Consider a hypothetical function called isEcmaGlobal that returns true for string names of ECMA-262 globals.考虑一个名为isEcmaGlobal的假设 function,它对 ECMA-262 全局变量的字符串名称返回true

$ node
> isEcmaGlobal('Array')
true
> isEcmaGlobal('process')
false

How would one design this function?如何设计这个 function?

Lets be careful here.让我们在这里小心。 We need to ask another question before this answer will make sense: Are we categorizing globals by what ECMA-262 ("the standard") says now , or by the standard governing our program's runtime?在这个答案有意义之前,我们需要问另一个问题:我们是按照 ECMA-262(“标准”)现在所说的,还是按照管理程序运行时的标准对全局变量进行分类?

Put another way: Should multiple machines see the same answers?换句话说:多台机器应该看到相同的答案吗?

Going by the Current Standard遵循现行标准

Let's say we want isEcmaGlobal to return true in terms of what the standard says right now .假设我们希望isEcmaGlobal根据标准现在所说的返回true I won't show any code here because if you care about this kind of problem, then you probably already thought to download or scrape standard global names.我不会在这里显示任何代码,因为如果您关心此类问题,那么您可能已经考虑过下载或抓取标准全局名称。

Going by the Current Runtime按当前运行时运行

Now let's assume we want isEcmaGlobal to return true in terms of offline information available in the current runtime.现在假设我们希望isEcmaGlobal根据当前运行时中可用的离线信息返回true It's not as easy as iterating over the "own" property names of the global object and checking them against a hard-coded array like ['Array', 'Object', ...] .这不像迭代全局 object 的“自己的”属性名称并对照硬编码数组(如['Array', 'Object', ...]检查它们那么容易。 If we did that, then we'd have to verify our array is correct.如果我们这样做了,那么我们必须验证我们的数组是否正确。 We can't verify hard-coded data because it assumes isEcmaGlobal is already written for that exact runtime, We cannot paste in global names from ECMA-262.我们无法验证硬编码数据,因为它假定isEcmaGlobal已经为该确切运行时编写,我们无法粘贴来自 ECMA-262 的全局名称。 because we don't know if the version of that document is in parity with the runtime.因为我们不知道该文档的版本是否与运行时相同。 We also can't check the Internet because we assumed an offline solution.我们也无法检查互联网,因为我们假设了离线解决方案。

So we can't hard code, but we can try something else.所以我们不能硬编码,但我们可以尝试别的东西。 I'll use Node.js v14.16.0 and its built-in vm module.我将使用 Node.js v14.16.0 及其内置的vm模块。 This program exploits vm 's need to provide standard globals in a new evaluator.该程序利用了vm在新评估器中提供标准全局变量的需要。 We tell vm to evaluate code using an empty global object, but that global object simply won't be empty.我们告诉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;
  }
}

Couple of things here.这里有几件事。

First, a warning: This example uses unsanitized code execution for illustration and brevity.首先,警告:此示例使用未经处理的代码执行来说明和简洁。 Do not put it on your clipboard with intent to take a shortcut.不要将其放在剪贴板上以采取捷径。

Second, you can see our goal is to create a fresh evaluator with only standard globals defined, and no visibility into what's going on outside of the evaluator ( eval does not do either of these things).其次,您可以看到我们的目标是创建一个新的评估器,只定义标准的全局变量,并且看不到评估器之外发生的事情( eval不会做这些事情中的任何一个)。 If we get that evaluator, then you can just toss Object.getOwnPropertyNames(new Function('return this')()) into it and we all go home.如果我们得到了那个评估器,那么你可以把Object.getOwnPropertyNames(new Function('return this')())扔进去,我们就都回家了。

But we're making a predicate, so assuming the "lean" global object is correct, evaluation will throw a ReferenceError for non-standard identifiers.但是我们正在做一个谓词,所以假设“精简”全局 object 是正确的,评估将为非标准标识符抛出一个ReferenceError

Unfortunately, somehting isn't right.不幸的是,有些事情是不对的。

> isEcmaGlobal('Array')
true
> isEcmaGlobal('process')
false // yes!
> isEcmaGlobal('global')
false // yes!!
> isEcmaGlobal('console')
true  // no!!!

Darn, we still have a Node global for some reason.该死,由于某种原因,我们仍然有一个全局节点。 So at this point you could say I'm making this all too complicated because Node.js doesn't add that many globals , or that I missed a configuration option or existing predicate.所以在这一点上,你可能会说我让这一切变得太复杂了,因为 Node.js 没有添加那么多 globals ,或者我错过了配置选项或现有谓词。 You'd be right on all counts, but that's missing the point of the question.你在所有方面都是对的,但这没有抓住问题的重点。 The question started with "Can a JavaScript program know...?", and my use of Node is meant to illustrate a way to approach the problem without hard-coding standard global names and creating a contradiction.问题以“ JavaScript 程序是否知道...?”开头,我使用 Node 旨在说明一种解决问题的方法,而无需硬编码标准全局名称并产生矛盾。 Even if Node.js added only one non-standard global, the problem remains if we can't get a clean evaluator.即使 Node.js 只添加了一个非标准全局,如果我们无法获得一个干净的评估器,问题仍然存在。

Recap回顾

To implement isEcmaGlobal in some JavaScript runtime, that runtime needs to give you a way to run a bare-bones JS evaluator, free of all host-specific extensions.要在某些JavaScript运行时中实现isEcmaGlobal ,该运行时需要为您提供一种运行基本 JS 评估器的方法,无需所有特定于主机的扩展。 eval doesn't count. eval不算。 Make it such that that you only accept identifiers, and then evaluate those identifiers.使您只接受标识符,然后评估这些标识符。 Interpret an exception as reason to return false .将异常解释为返回false的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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