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


当前回答

正如大家所注意到的:你不能。 但是你可以创建一个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

其他回答

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

考虑这个函数:

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访问值。

你有多少时间?

如果你ḧ̸̬̦̒͑͝ͅa̵͍͖t̴̪̟̬̖̾̋͗̏ͅe̸̳̍͌͝你的cpu,你可以通过每一个有效的变量名,并评估每一个,看看它是否会产生一个值!

下面的代码段尝试了前1000个bruteforce字符串,这足以在作用域内找到虚构的变量名:

let alpha = 'abcdefghijklmnopqrstuvwxyz'; let everyPossibleString = function*() { yield ''; for (let prefix of everyPossibleString()) for (let char of alpha) yield `${prefix}${char}`; }; let allVarsInScope = (iterations=1000) => { let results = {}; let count = 0; for (let bruteforceString of everyPossibleString()) { if (!bruteforceString) continue; // Skip the first empty string try { results[bruteforceString] = eval(bruteforceString); } catch(err) {} if (count++ > iterations) break; } return results; }; let myScope = (() => { let dd = 'ddd'; let ee = 'eee'; let ff = 'fff'; ((gg, hh) => { // We can't call a separate function, since that function would be outside our // scope and wouldn't be able to see any variables - but we can define the // function in place (using `eval(allVarsInScope.toString())`), and then call // that defined-in-place function console.log(eval(allVarsInScope.toString())()); })('ggg', 'hhh'); })();

这个脚本将最终(经过很长时间)找到所有作用域变量名称,以及abc nifty和swell,我创建的一些示例变量。注意,它只会找到由字母组成的变量名。

let preElem = document.getElementsByClassName('display')[0]; let statusElem = document.getElementsByClassName('status')[0]; let alpha = 'abcdefghijklmnopqrstuvwxyz'; alpha += alpha.toUpperCase(); let everyPossibleString = function*() { yield ''; for (let prefix of everyPossibleString()) for (let char of alpha) yield `${prefix}${char}`; }; (async () => { let abc = 'This is the ABC variable :-|'; let neato = 'This is the NEATO variable :-)'; let swell = 'This is the SWELL variable :-D'; let results = {}; let batch = 25000; let waitMs = 25; let count = 0; let startStr = null; for (let bruteStr of everyPossibleString()) { try { if (bruteStr === '') continue; if (startStr === null) startStr = bruteStr; try { results[bruteStr] = eval(bruteStr); } catch(err) {} if (count++ >= batch) { statusElem.innerHTML = `Did batch of ${batch} from ${startStr} -> ${bruteStr}`; preElem.innerHTML = JSON.stringify(results, null, 2); count = 0; startStr = null; await new Promise(r => setTimeout(r, waitMs)); } } catch(err) { // It turns out some global variables are protected by stackoverflow's snippet // system (these include "top", "self", and "this"). If these values are touched // they result in a weird iframe error, captured in this `catch` statement. The // program can recover by replacing the most recent `result` value (this will be // the value which causes the error). let lastEntry = Object.entries(results).slice(-1)[0]; results[lastEntry[0]] = '<a protected value>'; } } console.log('Done...'); // Will literally never happen })(); html, body { position: fixed; left: 0; top: 0; right: 0; bottom: 0; margin: 0; padding: 0; overflow: hidden } .display { position: fixed; box-sizing: border-box; left: 0; top: 0; bottom: 30px; right: 0; overflow-y: scroll; white-space: pre; font-family: monospace; padding: 10px; box-shadow: inset 0 0 10px 1px rgba(0, 0, 0, 0.3); } .status { position: fixed; box-sizing: border-box; left: 0; bottom: 0px; right: 0; height: 30px; line-height: 30px; padding: 0 10px; background-color: rgba(0, 0, 0, 1); color: rgba(255, 255, 255, 1); font-family: monospace; } <div class="display"></div> <div class="status"></div>

我非常清楚,这在任何情况下都是不现实的

正如大家所注意到的:你不能。 但是你可以创建一个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

是也不是。几乎在任何情况下都说“不”。“是的”,但如果您想检查全局作用域,则只能以有限的方式进行。举个例子:

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

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

在150多个其他东西中,输出如下:

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

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

一个更好的问题是,为什么要知道作用域内的变量是什么?

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

调试器;

直接进入浏览器控制台。