获取范围内的所有变量

IT技术 javascript
2021-01-20 04:27:26

有没有办法获取当前在 javascript 范围内的所有变量?

6个回答

虽然每个人都回答“”并且我知道“否”是正确的答案,但是如果您确实需要获取函数的局部变量,则有一种受限的方法。

考虑这个函数:

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

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

var s = f + '';

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

'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.js 中对此进行了测试。

但是这种方法问题在于你只是在函数本身中定义了变量。例如对于这个:

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

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

你能解释清楚“一个简单的评估”吗?我尝试使用以下代码,但无法将变量困在范围内。function getCounter(start){ return function(){ start ++; return start; } } var counter = getCounter(1); var startInClosure = eval.call(counter, 'this.start;'); console.log(startInClosure);它打印出来,undefined而我预计它应该是 2。
2021-03-11 04:27:26
@iman 感谢您的回答。我也猜这在 Javascript 端是不可能的,所以我猜在 v8 端是否可能。我发现以下问题链接准确地描述了我的问题。在其中 Lasse Reichstein 说不,但 mako-taco 说是。我尝试了一些 C++ 代码作为链接,但不知道如何编写它。
2021-03-19 04:27:26
@Pylipala 这里的问题是关于范围内的变量没有从范围外获取局部变量的值。这是不可能的,因为这是不应从外部访问的局部变量的定义。关于你的代码,你的意思是上下文而不是范围,但你没有把start放在上下文中(this),所以你不能用this.start阅读它请参阅此处:paste.ubuntu.com/11560449
2021-03-31 04:27:26
调用者的变量不一定是范围变量。此外,范围变量不一定在调用链中。已被关闭的变量可能会在从定义/闭包范围之外的调用者调用时被闭包函数引用(并且其变量根本无法从闭包的主体中访问)。
2021-04-03 04:27:26
解决原始问题的出色技术。值得点赞。
2021-04-08 04:27:26

不可以。“作用域内”变量由“作用域链”确定,不能以编程方式访问。

有关详细信息(很多),请查看 ECMAScript (JavaScript) 规范。这里有一个链接到官方页面,您可以下载该规范的规范(PDF格式),并且这里有一个官方的,可链接的HTML版本。

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

事件函数作用域内的变量取决于您定义事件函数的位置,而不是它们如何调用它。但是,通过this按照 KennyTM 指出的内容 ( for (var propName in ____))做一些事情,您可能会找到有关通过和参数对您的函数可用的内容的有用信息,因为这会告诉您提供给您的各种对象上的可用内容(this和参数;如果您是不确定他们给你什么参数,你可以通过arguments为每个函数隐式定义变量找到)。

因此,除了由于您定义函数的位置而在范围内的任何内容之外,您还可以通过以下方式找出其他可用的内容:

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 的开发工具(即使您通常不使用 Chrome 进行开发)或Firebug(即使您通常不使用 Firefox 进行开发)或 Opera 上的 Dragonfly 之类的调试器,或 IE 上的“F12 开发人员工具”。并通读他们为您提供的任何 JavaScript 文件。并击败他们以获得适当的文档。:-)

作为旁注,谷歌浏览器有一个很棒的调试器,可与 Firebug 相媲美(还有更多的锦上添花)。
2021-03-14 04:27:26
@tjcrowder 确实如此!我注意到答案上的时间戳是前一段时间:)
2021-03-29 04:27:26
@Swivelgames:哦,相比 Firefox+Firebug,我更喜欢 Chrome 的开发工具。他们只是在 2010 年并没有达到多少。:-)
2021-04-03 04:27:26

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

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变量不包括在内。

受到Bergi这个回答启发

对于如此简单的技术来说,这是令人惊讶的成功。
2021-03-14 04:27:26
哇超能力
2021-03-17 04:27:26
这是什么伏都教巫术
2021-03-21 04:27:26
function 声明也不包括在内
2021-04-08 04:27:26

是和否。几乎在所有情况下都是“不”。“是”,但仅限于有限的方式,如果您想检查全局范围。以下面的例子为例:

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

所以可以列出当前作用域中的一些变量,但并不可靠、简洁、高效或易于访问。

一个更好的问题是为什么你想知道哪些变量在范围内?

我为hasOwnProperty 添加了一行检查。例如:for ( var i in window ) { if (window.hasOwnProperty(i)) { console.log(i, window[i]); }}这至少会减少继承的属性,并且您的变量将仅包含大约 50 个其他属性。
2021-03-11 04:27:26
我认为这个问题更笼统,不限于 Web 浏览器上下文中的 javascript。
2021-03-21 04:27:26
如果您使用节点,只需将“窗口”一词更改为“全局”……或者您可以使用“this”一词,但在“use strict”下是禁止的
2021-03-27 04:27:26
为什么不应该有人至少想要在调试和/或开发目的期间检查哪些变量在范围内。
2021-03-28 04:27:26
想知道局部作用域中有哪些变量的另一个原因是序列化一个闭包。
2021-03-29 04:27:26

你不能。

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

也可以看看:

+1 链接到 bclary.com。最新规范的 HTML 版本将在未来几个月内出现在 ECMA 网站上,我很高兴地说。
2021-03-14 04:27:26
2021-03-31 04:27:26
请注意,两个链接都已损坏。
2021-04-07 04:27:26
是的,但是范围内的变量不仅仅是当前的变量对象。作用域内变量由作用域链确定,作用域链是(在正常情况下)由一系列变量对象组成并以全局对象终止with的链(尽管该语句可用于在链中插入其他对象)。
2021-04-09 04:27:26