关于javascript:获取范围内的所有变量

Getting All Variables In Scope

有没有一种方法可以获取当前在javascript范围内的所有变量?


虽然每个人都回答"不",我知道"不"是正确的答案,但如果你真的需要得到一个函数的局部变量,有一个限制的方法。

考虑这个函数:

1
2
3
4
var f = function() {
    var x = 0;
    console.log(x);
};

您可以将函数转换为字符串:

1
var s = f + '';

您将得到作为字符串的函数源

1
2
3
4
'function () {
var x = 0;
console.log(x);
}'

现在您可以使用像esprima这样的解析器来解析函数代码和查找局部变量声明。

1
2
3
4
5
6
7
var s = 'function () {
var x = 0;
console.log(x);
}'
;
s = s.slice(12); // to remove"function ()"
var esprima = require('esprima');
var result = esprima.parse(s);

查找对象时使用:

1
obj.type =="VariableDeclaration"

结果(我删除了下面的EDOCX1[0]):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
   "type":"Program",
   "body": [
        {
           "type":"VariableDeclaration",
           "declarations": [
                {
                   "type":"VariableDeclarator",
                   "id": {
                       "type":"Identifier",
                       "name":"x"
                    },
                   "init": {
                       "type":"Literal",
                       "value": 0,
                       "raw":"0"
                    }
                }
            ],
           "kind":"var"
        }
    ]
}

我已经在chrome、firefox和node中测试过这个。

但是这个方法的问题是你只需要在函数本身中定义变量。例如,对于这一个:

1
2
3
4
5
6
7
var g = function() {
    var y = 0;
    var f = function() {
        var x = 0;
        console.log(x);
    };
}

你只需要进入X而不是Y。但仍然可以在循环中使用调用方链(arguments.callee.caller.caller.caller)来查找调用方函数的局部变量。如果您有所有的局部变量名,那么您就有了范围变量。通过变量名,您可以使用简单的eval访问值。


不,"范围内"变量是由"范围链"决定的,不能通过编程方式访问。

有关详细信息(相当多),请查看ecmascript(javascript)规范。这里有一个到官方页面的链接,您可以在那里下载规范规范规范(PDF),这里有一个到官方的、可链接的HTML版本。

根据您对Camsoft的评论进行更新

事件函数作用域中的变量由定义事件函数的位置决定,而不是由它们如何调用。但是,您可以通过this找到关于您的函数可用的内容和参数的有用信息,方法是按照kennytm所指出的(for (var propName in ____))进行一些操作,因为这将告诉您在提供给您的各种对象(this和参数上可用的内容;如果您不确定它们提供给您的参数是什么,您可以使用通过为每个函数隐式定义的arguments变量进行查找)。

因此,除了在范围内定义函数的位置之外,您还可以通过执行以下操作找到其他可用的方法:

1
2
3
4
5
6
7
8
9
10
11
12
var n, arg, name;
alert("typeof this =" + typeof this);
for (name in this) {
    alert("this[" + name +"]=" + this[name]);
}
for (n = 0; n < arguments.length; ++n) {
    arg = arguments[n];
    alert("typeof arguments[" + n +"] =" + typeof arg);
    for (name in arg) {
        alert("arguments[" + n +"][" + name +"]=" + arg[name]);
    }
}

(您可以在此基础上展开以获取更多有用的信息。)

不过,与此相反,我可能会使用像chrome的dev工具(即使您通常不使用chrome进行开发)或firebug(即使您通常不使用firefox进行开发),或者在opera上使用dragonfly,或者在ie上使用f12开发人员工具,并阅读他们提供给您的任何javascript文件。打他们的头找合适的医生。-)


是和否。几乎在所有情况下都是"不"。是的,"但是只有在有限的方式下,如果你想检查全局范围的话。举个例子:

1
2
3
4
5
var a = 1, b = 2, c = 3;

for ( var i in window ) {
    console.log(i, typeof window[i], window[i]);
}

在150多件其他事情中,其输出如下:

1
2
3
4
5
6
7
8
9
10
getInterface function getInterface()
i string i // <- there it is!
c number 3
b number 2
a number 1 // <- and another
_firebug object Object firebug=1.4.5 element=div#_firebugConsole
"Firebug command line does not support '$0'"
"Firebug command line does not support '$1'"
_FirebugCommandLine object Object
hasDuplicate boolean false

因此,在当前范围内列出一些变量是可能的,但它不可靠、简洁、高效或容易访问。

一个更好的问题是,为什么要知道范围中有哪些变量?


在ecmascript 6中,通过使用代理对象将代码包装在with语句中,或多或少是可能的。注意,这需要非严格的模式,这是不好的做法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function storeVars(target) {
  return new Proxy(target, {
    has(target, prop) { return true; },
    get(target, prop) { return (prop in target ? target : window)[prop]; }
  });
}
var vars = {}; // Outer variable, not stored.
with(storeVars(vars)) {
  var a = 1;   // Stored in vars
  var b = 2;   // Stored in vars
  (function() {
    var c = 3; // Inner variable, not stored.
  })();
}
console.log(vars);

代理声明拥有with中引用的所有标识符,因此变量分配存储在目标中。对于查找,代理从代理目标或全局对象(而不是父范围)中检索值。不包括letconst变量。

灵感来自于伯吉的回答。


你不能。

变量、函数声明的标识符和函数代码的参数被绑定为变量对象的属性,这是不可访问的。

另请参见:

  • 范围链和标识符解析


在特定范围内访问var的最简单方法

  • 打开开发人员工具>资源(在chrome中)
  • 使用可以访问该范围的函数打开文件(提示cmd/ctrl+p以查找文件)
  • 在函数内部设置断点并运行代码
  • 当它在断点处停止时,您可以通过控制台(或scope var窗口)访问scope var。
  • 注意:您要针对未缩小的JS执行此操作。

    显示所有非私有变量的最简单方法

  • 打开控制台(镀铬)
  • 类型:this.window
  • 按Enter键
  • 现在,您将看到一个对象树,您可以用所有声明的对象展开它。


    大家都注意到了:你不能。但您可以创建一个对象并将您声明的每个var分配给该对象。这样您就可以轻松地查看vars:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var v = {}; //put everything here

    var f = function(a, b){//do something
    }; v.f = f; //make's easy to debug
    var a = [1,2,3];
    v.a = a;
    var x = 'x';
    v.x = x;  //so on...

    console.log(v); //it's all there


    如果只想手动检查变量以帮助调试,只需启动调试器:

    江户十一〔一〕号

    直接进入浏览器控制台。


  • 从一开始就有人以任何方式或方式书写或打字过的每一个单词的列表(绝对是数学意义上的有限列表)。

  • 通过在开发人员控制台中再次输入它们(作为字符串),将它们全部放入一个大数组中,这样就不会在这里引发错误。

  • 创建新数组,并在有限列表上执行循环,如果由于引用错误(使用eval"unstring",因为如果不在范围内,您希望在此处出现错误),则在try/catch(仅在try中执行)未在catch中结束时将其推入新数组。

  • 我收回它。我在第1点提到的列表不够大。他们可以通过window[randomlyGeneratedString]=创建变量。更好的循环所有的字符串,这些字符串可以由停在合理可行的时间范围内的任何计算机程序生成,例如,自计算机发明以来的时间。

  • 好吧,说真的,你可以这样做,用1)在整个代码库上运行esprima.parse,在树上遍历名为"identifier"的东西,并存储它们的"name"得到什么。但是,您将错过正在创建的变量,如窗口["file"+i]=blah中所示,请参见4。