ima*_*man 91
虽然每个人都回答" 否 ",但我知道"否"是正确的答案,但如果你真的需要获得函数的局部变量,那么就有一种限制的方式.
考虑这个功能:
var f = function() {
var x = 0;
console.log(x);
};
Run Code Online (Sandbox Code Playgroud)
您可以将函数转换为字符串:
var s = f + '';
Run Code Online (Sandbox Code Playgroud)
您将获得函数源作为字符串
'function () {\nvar x = 0;\nconsole.log(x);\n}'
Run Code Online (Sandbox Code Playgroud)
现在,您可以使用像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);
Run Code Online (Sandbox Code Playgroud)
并找到对象:
obj.type == "VariableDeclaration"
Run Code Online (Sandbox Code Playgroud)
在结果中(我已删除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"
}
]
}
Run Code Online (Sandbox Code Playgroud)
我已经在Chrome,Firefox和Node中对此进行了测试.
但是这个方法的问题在于你只需要在函数本身中定义变量.例如这个:
var g = function() {
var y = 0;
var f = function() {
var x = 0;
console.log(x);
};
}
Run Code Online (Sandbox Code Playgroud)
你只能访问x而不是y.但是你仍然可以在循环中使用调用者链(arguments.callee.caller.caller.caller)来查找调用函数的局部变量.如果您有所有本地变量名称,那么您有范围变量.使用变量名称,您可以使用简单的eval访问值.
T.J*_*der 82
否."范围内"变量由"范围链"确定,该范围链无法以编程方式访问.
有关详细信息(非常多),请查看ECMAScript(JavaScript)规范.这里是官方页面的链接,您可以在其中下载规范规范(PDF),这里是官方可链接HTML版本的链接.
根据您对Camsoft的评论进行更新
事件函数范围内的变量取决于您定义事件函数的位置,而不是它们如何调用它.但是,您可以通过thisKennyTM指出的方式(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]);
}
}
Run Code Online (Sandbox Code Playgroud)
(您可以扩展它以获得更多有用的信息.)
不过,我可能会使用像Chrome开发工具这样的调试器(即使你通常不使用Chrome进行开发)或Firebug(即使你通常不使用Firefox进行开发),也可能使用Opera上的Dragonfly ,或IE上的"F12开发人员工具".并阅读他们为您提供的任何JavaScript文件.并且为了正确的文档而击败他们.:-)
Jus*_*son 32
是的,不是.几乎在所有情况下都"不"."是的,"但是只有在有限的方式,如果你想检查全球范围.请看以下示例:
var a = 1, b = 2, c = 3;
for ( var i in window ) {
console.log(i, typeof window[i], window[i]);
}
Run Code Online (Sandbox Code Playgroud)
其中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
Run Code Online (Sandbox Code Playgroud)
因此,可以在当前范围中列出一些变量,但它不可靠,简洁,高效或易于访问.
一个更好的问题是为什么你想知道范围内的变量是什么?
Ori*_*iol 18
在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);Run Code Online (Sandbox Code Playgroud)
代理声称拥有内部引用的所有标识符with,因此变量赋值存储在目标中.对于查找,代理将从代理目标或全局对象(而不是父作用域)中检索值.let和const变量不包括在内.
我做了一个小提琴实现(基本上)上述 iman 概述的想法。这是当您将鼠标悬停在第二个 ipsum 上时的外观return ipsum*ipsum - ...
范围内的变量在声明它们的地方突出显示(不同的范围用不同的颜色)。在lorem与红色边框是一个阴影变量(不在范围内,但在范围上,如果其他LOREM进一步下跌的树不会在那里。)
我正在使用 esprima 库来解析 JavaScript,以及 estraverse、escodegen、escope(esprima 之上的实用程序库。)“繁重的工作”全部由这些库完成(当然,最复杂的是 esprima 本身。)
这个怎么运作
ast = esprima.parse(sourceString, {range: true, sourceType: 'script'});
Run Code Online (Sandbox Code Playgroud)
制作抽象语法树。然后,
analysis = escope.analyze(ast);
Run Code Online (Sandbox Code Playgroud)
生成一个复杂的数据结构,封装有关程序中所有范围的信息。其余的工作是将在该分析对象(以及抽象语法树本身)中编码的信息收集在一起,并从中制定出交互式着色方案。
所以正确的答案实际上不是“不”,而是“是的,但是”。“但是”很重要:您基本上必须用 JavaScript 重写 chrome 浏览器(及其开发工具)的重要部分。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
Run Code Online (Sandbox Code Playgroud)
注意:您希望针对未缩小的js执行此操作.
现在,您将看到一个对象树,您可以使用所有声明的对象进行扩展.
如果你讨厌你的 CPU,你可以暴力破解每个有效的变量名,并eval查看每个变量名是否产生一个值!
以下代码段尝试前 1000 个蛮力字符串,这足以在范围内找到人为的变量名称:
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');
})();Run Code Online (Sandbox Code Playgroud)
该脚本将最终(经过很长的时间)找到所有范围的变量名称,以及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
})();Run Code Online (Sandbox Code Playgroud)
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;
}Run Code Online (Sandbox Code Playgroud)
<div class="display"></div>
<div class="status"></div>Run Code Online (Sandbox Code Playgroud)
我非常清楚几乎没有任何情况下这是可行的
| 归档时间: |
|
| 查看次数: |
105153 次 |
| 最近记录: |