是否有一种方法来获得目前在javascript范围内的所有变量?


当前回答

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

打开开发人员工具>资源(Chrome) 打开具有该范围的函数的文件(提示cmd/ctrl+p来查找文件) 在该函数中设置断点并运行代码 当它停在断点时,您可以通过控制台(或范围变量窗口)访问范围变量。

注意:你想对未最小化的js做这个操作。

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

打开控制台(Chrome) 类型:this.window 回车

现在你将看到一个对象树,你可以展开所有已声明的对象。

其他回答

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

打开开发人员工具>资源(Chrome) 打开具有该范围的函数的文件(提示cmd/ctrl+p来查找文件) 在该函数中设置断点并运行代码 当它停在断点时,您可以通过控制台(或范围变量窗口)访问范围变量。

注意:你想对未最小化的js做这个操作。

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

打开控制台(Chrome) 类型:this.window 回车

现在你将看到一个对象树,你可以展开所有已声明的对象。

您可以在[[scopes]]中看到作用域及其变量,甚至可以使用console.dir()查看闭包作用域。

示例1:

counterWithClosure = (function () {
    let internalVar = 0
    return function () {
        return ++internalVar
    }
})()

counterWithClosure() // 1
counterWithClosure() // 2
counterWithClosure() // 3

console.dir(counterWithClosure)

它会显示“[[Scopes]] > Closure”,“[[Scopes]] > Global”,甚至“[[Scopes]] > Script”中的变量,如果页面有脚本可达的话。

图片输出:

即使使用嵌套闭包,也可以看到嵌套作用域。

示例2:

adderWithNestedClosures = (function () {
    let varLevel1 = 1
    return function (param1) {
        let varLevel2 = 10
        return function (param2) {
            let varLevel3 = 100
            return function (param3) {
                let varLevel4 = 1000
                return function (param4) {
                    ++varLevel1
                    ++varLevel2
                    ++varLevel3
                    ++varLevel4
                    return {
                        paramsSum: param1 + param2 + param3 + param4,
                        varsSum: varLevel1 + varLevel2 + varLevel3 + varLevel4
                    }
                }
            }
        }
    }
})()

adderWith123 = adderWithNestedClosures(1)(2)(3) // Preparing function with nested scopes
adderWith123(4) // {paramsSum:10,varsSum:1115}
adderWith123(4) // {paramsSum:10,varsSum:1119}
adderWith123(5) // {paramsSum:11,varsSum:1123}
console.dir(adderWith123) 

它显示了[[scopes]]中的所有嵌套作用域 图片输出:

它适用于基于chromium的浏览器。

正如大家所注意到的:你不能。 但是你可以创建一个obj并将你声明的每个var赋值给那个obj。 这样你就可以很容易地检查你的vars:

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

我做了一个小提琴实现(本质上)以上的想法概述iman。下面是当你把鼠标放在第二个ipsum上,返回ipsum*ipsum -…

范围内的变量在声明的地方突出显示(不同的范围使用不同的颜色)。带红色边界的lorem是一个阴影变量(不在范围内,但如果树下的另一个lorem不在那里,那么它就在范围内)。

我使用esprima库来解析JavaScript,以及estraverse, escodegen, escope(在esprima之上的实用程序库)。“繁重的工作”全部由这些库完成(当然,最复杂的是esprima本身)。

它是如何工作的

ast = esprima.parse(sourceString, {range: true, sourceType: 'script'});

生成抽象语法树。然后,

analysis = escope.analyze(ast);

生成一个复杂的数据结构,其中封装有关程序中所有作用域的信息。其余的工作是收集该分析对象(以及抽象语法树本身)中编码的信息,并从中生成交互式着色方案。

所以正确的答案实际上不是“不”,而是“是的,但是”。“但是”是一个很大的问题:你基本上必须用JavaScript重写chrome浏览器(以及devtools)的重要部分。JavaScript是一种图灵完备语言,所以原则上这当然是可能的。不可能的是不使用源代码的全部(作为字符串),然后用它来做非常复杂的事情。

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

考虑这个函数:

var f = function() {
    var x = 0;
    console.log(x);
};

你可以把你的函数转换成一个字符串:

var s = f + '';

你会得到一个字符串形式的source of function

'function () {\nvar x = 0;\nconsole.log(x);\n}'

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

var s = 'function () {\nvar x = 0;\nconsole.log(x);\n}';
s = s.slice(12); // to remove "function () "
var esprima = require('esprima');
var result = esprima.parse(s);

并找到对象:

obj.type == "VariableDeclaration"

在结果中(我已经删除了console.log(x)下面):

{
    "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中进行了测试。

但是这个方法的问题是你只有函数本身定义的变量。举个例子:

var g = function() {
    var y = 0;
    var f = function() {
        var x = 0;
        console.log(x);
    };
}

你只能得到x,而不是y。 但是仍然可以在循环中使用调用者链(arguments.callee.caller.caller.caller)来查找调用者函数的局部变量。如果你有所有的局部变量名,那么你就有了作用域变量。通过变量名,您可以通过简单的eval访问值。