javascript 获取函数体

问题描述 投票:0回答:8

我有一个功能,例如

var test = function () {alert(1);}

如何获取这个函数的主体?

我认为唯一的方法是解析 test.toString() 方法的结果,但是还有其他方法吗?如果解析是唯一的方法,那么到达正文的正则表达式是什么? (非常需要正则表达式的帮助,因为我对它们不熟悉)

javascript regex
8个回答
53
投票

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);"

12
投票

2015年更新

重新审视函数反编译的状态,可以说它在某些经过深思熟虑的用例和环境中通常是安全的(例如:具有用户定义函数的 Node.js 工作线程)。

它应该与 eval 放在同一桶中,这是一个有其地位的强大工具,但只应在极少数情况下使用。 三思而后行,这是我唯一的建议。

Kangax新研究的结论

  • 仍然不标准
  • 用户定义的函数通常看起来很正常
  • 奇怪的引擎(特别是当涉及到源代码时 位置、空格、注释、死代码)
  • 可能会有未来的奇怪引擎(特别是移动或不寻常的引擎) 具有保守内存/功耗的设备)
  • 绑定函数不显示其原始来源(但保留 标识符...有时)
  • 您可能会遇到 非标准扩展(如 Mozilla 的表达式 关闭)
  • ES6 即将到来,函数现在看起来与 他们曾经
  • 缩小器/预处理器不是你的朋友

“函数反编译”——获取的过程 Function 对象的字符串表示形式。

函数反编译一般是 推荐反对,因为它是 非标准语言的一部分,以及 结果,导致代码被 不可互操作和潜在的 容易出错

@kangax 于 comp.lang.javascript


6
投票

最简单的用例

如果您只想执行函数体(例如使用

eval
或使用
Worker
API),您可以简单地添加一些代码来规避提取函数体的所有陷阱(如上所述一般而言,这是一个坏主意):

'(' + myFunction + ')()';

我在this

Worker
相关的JSFiddle中使用这个技巧。

具有准确堆栈跟踪的完整函数序列化

我还编写了一个更完整的库,可以:

  1. 将任何类型的函数序列化为字符串
  2. 能够将该字符串表示形式发送到其他任何地方,使用任何自定义参数执行它,并且能够重现原始堆栈跟踪

在这里查看我的

CodeBuilder
代码

请注意,大部分代码负责确保我们在稍后的时间点执行序列化函数时获得准确的堆栈跟踪。

这个小提琴演示了该逻辑的简化版本:

  1. 使用
    JSON.stringify
    正确序列化函数(例如,当我们想要将其作为更大的序列化“数据包”的一部分时,这会派上用场)。
  2. 然后我们将其包装在一个
    eval
    中以取消转义“JSON-ish”转义字符串(JSON不允许函数+代码,所以我们必须使用
    eval
    ),然后在另一个
    eval
    中得到返回我们想要的对象。
  3. 我们还使用
    //# sourceMappingURL
    (或旧版本
    //@ sourceMappingURL
    )在堆栈跟踪中显示正确的函数名称。
  4. 您会发现 Stacktrace 看起来不错,但它没有为您提供与我们在其中定义序列化函数的文件相关的正确行和列信息,这就是为什么我的
    Codebuilder
    使用 stacktracejs 来解决这个问题.

我在我的(现在有点过时的)RPC 库中使用

CodeBuilder
的东西,你可以在其中找到一些如何使用它的示例:

  1. serializeInlineFunction
    示例
  2. serializeFunction
    示例
  3. buildFunctionCall
    示例

3
投票

扩展@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注释


2
投票

此代码在使用 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 接受的答案的编辑,但由于更改被认为过于剧烈而被拒绝。


0
投票
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. 的提案解决方案没有脸书。


0
投票

您可以尝试一下这个功能:

function extractFunctionBody(fn) {
    var reg = /function \((.*)\)[ ]?{(.*)}$/g;
    var match = reg.exec(fn.toString().replace(/\n/g, ";"));
    if (match){
        return match[2];
    } else {
        return "";
    }
}

-1
投票

试试这个:

/\{(\s*?.*?)*?\}/g.exec(test.toString())[0]

test.toString() 将保存您的整个声明。

/{(\s*?.?)?}/g 将匹配大括号之间的所有内容

© www.soinside.com 2019 - 2024. All rights reserved.