我有一个功能,例如
var test = function () {alert(1);}
如何获取这个函数的主体?
我认为唯一的方法是解析 test.toString() 方法的结果,但是还有其他方法吗?如果解析是唯一的方法,那么到达正文的正则表达式是什么? (非常需要正则表达式的帮助,因为我对它们不熟悉)
IF(!!!)你可以得到
toString()
,然后你可以简单地从第一个indexOf("{")
到lastIndexOf("}")
取子串。所以,像这样的东西“有效”(如在 ideone.com 上看到的):
var test = function () {alert(1);}
var entire = test.toString(); // this part may fail!
var body = entire.substring(entire.indexOf("{") + 1, entire.lastIndexOf("}"));
print(body); // "alert(1);"
2015年更新
重新审视函数反编译的状态,可以说它在某些经过深思熟虑的用例和环境中通常是安全的(例如:具有用户定义函数的 Node.js 工作线程)。
它应该与 eval 放在同一桶中,这是一个有其地位的强大工具,但只应在极少数情况下使用。 三思而后行,这是我唯一的建议。
“函数反编译”——获取的过程 Function 对象的字符串表示形式。
函数反编译一般是 推荐反对,因为它是 非标准语言的一部分,以及 结果,导致代码被 不可互操作和潜在的 容易出错。
@kangax 于 comp.lang.javascript
如果您只想执行函数体(例如使用
eval
或使用 Worker
API),您可以简单地添加一些代码来规避提取函数体的所有陷阱(如上所述一般而言,这是一个坏主意):
'(' + myFunction + ')()';
我在this
Worker
相关的JSFiddle中使用这个技巧。
我还编写了一个更完整的库,可以:
CodeBuilder
代码。
请注意,大部分代码负责确保我们在稍后的时间点执行序列化函数时获得准确的堆栈跟踪。
这个小提琴演示了该逻辑的简化版本:
JSON.stringify
正确序列化函数(例如,当我们想要将其作为更大的序列化“数据包”的一部分时,这会派上用场)。eval
中以取消转义“JSON-ish”转义字符串(JSON不允许函数+代码,所以我们必须使用eval
),然后在另一个eval
中得到返回我们想要的对象。//# sourceMappingURL
(或旧版本 //@ sourceMappingURL
)在堆栈跟踪中显示正确的函数名称。Codebuilder
使用 stacktracejs 来解决这个问题.我在我的(现在有点过时的)RPC 库中使用
CodeBuilder
的东西,你可以在其中找到一些如何使用它的示例:
扩展@polygenelubricants'答案:
.toString()
测试者:
var y = /* olo{lo} */
/* {alala} */function/* {ff} */ x/*{s}ls{
}ls*/(/*{*{*/)/* {ha-ha-ha} */
/*
it's a function
*/
{
return 'x';
// }
}
/*
*/
indexOf
和lastIndexOf
:
function getFunctionBody(fn) {
function removeCommentsFromSource(str) {
return str.replace(/(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm, '$1');
}
var s = removeCommentsFromSource( fn.toString() );
return s.substring(s.indexOf('{')+1, s.lastIndexOf('}'));
};
getFunctionBody(y);
/*
"
return 'x'
"
*/
使用:来自js源的rm注释
此代码在使用 ES6 箭头函数(例如
var testFn=(q)=>q+1;
)时提供主体
function getFunctionBody(test){
var entire = test.toString(); // note: not safe-guarded; this part may fail like this!
return entire.substring((entire.indexOf("{")+1)||(entire.indexOf("=>")+2), entire.lastIndexOf("}")!==-1?entire.lastIndexOf("}"):entire.length);
}
//testing/showcase code
var tests = [
function () {alert(1);},
()=>{return 1;},
q=>q+1
];
for (var i=0;i<tests.length;i++){
console.log(tests[i],getFunctionBody(tests[i]));
}
我最初提交此代码作为对 Polygenelubricants 接受的答案的编辑,但由于更改被认为过于剧烈而被拒绝。
var fn1 = function() {};
var fn2 = function() { alert("lol!"); };
Function.prototype.empty = function() {
var x = this.toString().match(/\s*function\s*\w*\s*\(.*?\)\s*{\s*}\s*;?\s*/);
return x != null;
};
alert(fn1.empty()); // true
alert(fn2.empty()); // false
' 保罗·托雷斯 (Paulo Torres) 集团 A.P.D.A. 的提案解决方案没有脸书。
您可以尝试一下这个功能:
function extractFunctionBody(fn) {
var reg = /function \((.*)\)[ ]?{(.*)}$/g;
var match = reg.exec(fn.toString().replace(/\n/g, ";"));
if (match){
return match[2];
} else {
return "";
}
}
试试这个:
/\{(\s*?.*?)*?\}/g.exec(test.toString())[0]
test.toString() 将保存您的整个声明。
/{(\s*?.?)?}/g 将匹配大括号之间的所有内容