声明Javascript变量的所有可能方式

7
为了创建一个能够自动补全用户声明的所有变量,但对于其他变量(如 Math.PI 甚至模块 Math)毫不知情的 IDE,该 IDE 需要能够识别与用户声明的变量相关的所有标识符。 假设您已经可以访问程序的 AST(抽象符号表),那么什么机制可以用来捕获所有这些变量呢?
我正在使用 reflect.js (https://github.com/zaach/reflect.js) 生成 AST。

4
在第三个中,只有 m 被声明了。abc 不是变量,它们是对象的属性。 - gen_Eric
1
@ŠimeVidas:k已经声明了,它是全局的。 - gen_Eric
2
@BlackVegetable 你的目标是什么?术语的误用使问题难以理解。在JavaScript中,只有几种方法可以声明变量;你展示的不仅仅是声明。 - Rob W
2
如果你正在编写自己的解析器/编译器,你可能想要查看规范 - Reinstate Monica -- notmaynard
2
此外,对于这个问题,大多数答案都已经过时了。@版主们?应该怎么办?标记一个?标记多个?还是给他们点踩让作者自己处理? - rlemon
显示剩余23条评论
2个回答

7

我认为这几乎是不可能的

以下是我认为在不执行它的情况下几乎不可能的原因:

让我们从易到难地遍历未探索的部分。

易于捕捉:

函数作用域在此处被忽略:

(function(x){
    //x is now an object with an a property equal to 3
    // for the scope of that IIFE.
    x;
})({a:3});

这里有一些有趣的技巧分享给大家:

介绍一下...鼓点声...块级作用域!!

with({x:3}){
    x;//x is now declared in the scope of that with and is equal to 3.
}


try{ throw 5}catch(x){ 
    x // x is now declared in the scope of the try block and is equal to 5;
}

(读者请注意:我恳求您不要在实际的代码作用域中使用这两个方法:)

不容易:

方括号表示法:

var n = "lo";
a["h"+"e"+"l"+n] = "world"; // need to understand that a.hello is a property.
                        // not a part of the ast!

真正困难的部分:

我们不要忘记调用编译器这些在AST中不会显示:

eval("var x=5"); // declares x as 5, just a string literal and a function call
new Function("window.x = 5")();// or global in node 

在node.js中,这也可以使用vm模块完成。在浏览器中,可以使用document.write或脚本标记注入。当然,他们还可以尽可能地混淆代码。
new Function(["w","i","n","dow.x"," = ","5"].join(""))(); // Good luck finding this!
new Function('new Function(["w","i","n","dow.x"," = ","5"].join(""))()')();// Getting dizzy already?

那么该怎么办呢?

  • 在更新符号表(仅相关部分)时,在一个封闭的、定时的环境中执行代码。
  • 查看从执行中生成的符号表。
  • 嘭,你就得到了一个符号表。

这并不可靠,但它可能是你能得到的最接近结果。

我所能想到的唯一其他选择——也是大多数IDE所做的——就是简单地忽略任何非:

object.property = ... //property definition
var a = ... //scoped
b = ... //global, or error in strict mode
function fn(){ //function declaration
object["property"] //property with a _fixed_ literal in bracket notation.

还有,函数参数。

我没有看到过任何一款IDE能够处理除此以外的内容。因为它们是迄今为止最常见的,所以我认为将它们计算在内是完全合理的。


在编辑过的问题之后,他想要的是可能的。AST提供了足够的信息。诀窍在于从大量数据中提取所需的信息。现实世界的应用程序表明,可以提取这样的信息:JSHint、UglifyJS、Google Closure编译器 - 它们都跟踪变量分配。 - Rob W
2
哦天啊...这个答案的恐怖程度是传奇般的。我再也不会以同样的方式看待Javascript了。 - BlackVegetable
@RobW 这些工具(JSHint、UglifyJS、Closure Compiler)都无法找到动态定义,如果我将一个字符串解密为 eval,它们都无法捕获它(也不应该期望它们这样做)。IDE 和 linter 非常好用,我很喜欢它们,但有些东西对它们来说是不合理的。如果你看到我如何得出我的答案,我认为它很好地总结了这个问题:“我没有看到任何 IDE 能够处理除这些之外的任何东西。由于它们远远是最常见的,我认为把它们算进去是完全合理的。” - Benjamin Gruenbaum

-2
通过将它们添加到已经存在的对象上....即
window.mynewvar = 5;
function mynewfunc() {

}

1
@Rocket:毕竟,所有的JavaScript变量不都只是属性吗? - Rake36
1
@Rake36:我不会这么说。如果你有function abc(){ var x = 12; }呢?在这种情况下,x不是任何东西的属性。 - gen_Eric
1
@Braden:不存在所谓的“本地对象”。 - gen_Eric
@RocketHazmat 你说得对。变量只能在函数作用域中定义。当你向对象添加新属性时,仍然在“声明”变量,否则在全局作用域中执行类似var a = 5的操作将不被视为声明。 - Braden
1
@Rocket:我必须同意你的观点,并承认属性和本地作用域(私有)变量之间的区别。我天真地以为本地_var_可以通过某种属性访问器访问,但我找不到这样的方法。 - Rake36
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接