javascript获取功能体

时间:2010-07-05 13:30:02

标签: javascript regex

我有一个功能,例如

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

如何获得此功能的主体?

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

8 个答案:

答案 0 :(得分:43)

IF(!!!) 您可以获取toString(),然后您可以简单地将第一个indexOf("{")的子字符串带到lastIndexOf("}")。所以,这样的“工作”(as seen on 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);"

答案 1 :(得分:10)

2015年更新

在重新访问函数反编译的状态后,可以说它在某些考虑周全的用例和环境中通常是安全的(例如:Node.js worker with users定义的功能)。

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

Kangax's new research的结论:

  • 它仍然不标准
  • 用户定义的功能通常看起来很清晰
  • 奇怪的引擎(特别是在源代码方面 放置,空白,评论,死代码)
  • 可能会有未来奇怪的引擎(特别是移动或异常 具有保守内存/功耗的设备)
  • 绑定函数不显示其原始来源(但请保留 标识符...有时候)
  • 您可能遇到非标准扩展程序(就像Mozilla的表达式一样) 封)
  • ES6即将推出,功能现在看起来非常不同了 他们曾经
  • Minifiers / preprocessors 不是您的朋友

  

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

     

函数反编译通常是   建议反对,因为它是   非标准部分语言,以及   结果,导致代码存在   不可互操作且可能   的易错

comp.lang.javascript

上的@kangax

答案 2 :(得分:6)

最简单的用例

如果你只想执行函数体(例如使用eval或使用Worker API),你可以简单地添加一些代码来规避提取体的所有缺陷。功能(正如其他人所说,一般来说是一个坏主意):

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

我在this Worker-related JSFiddle中使用此技巧。

具有精确Stacktrace的完整功能序列化

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

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

    请注意,大部分代码都会确保我们获得准确的堆栈跟踪,无论我们在以后执行序列化函数的哪个位置。

    This fiddle演示了该逻辑的简化版本:

    1. 使用JSON.stringify正确序列化该功能(例如,当我们想让它成为更大的序列化“数据包”的一部分时,它会派上用场。)
    2. 然后我们将它包装在一个eval中以取消转义“JSON-ish”-escaped字符串(JSON不允许函数+代码,因此我们必须使用eval),然后在另一个eval来取回我们想要的对象。
    3. 我们还使用//# sourceMappingURL(或旧版本//@ sourceMappingURL)在堆栈跟踪中显示正确的函数名称。
    4. 您会发现Stacktrace看起来没问题,但它没有为您提供与我们定义序列化函数的文件相关的正确行和列信息,这就是我的Codebuilder使用{{{ 3}}来解决这个问题。
    5. 我在我的(现在稍微陈旧的)RPC库中使用CodeBuilder内容,您可以在其中找到一些如何使用它的示例:

      1. stacktracejs
      2. serializeInlineFunction example
      3. serializeFunction example

答案 3 :(得分:3)

扩展@polygenelubricants'answer

使用:.toString()

<强>测试对象:

var y = /* olo{lo} */
    /* {alala} */function/* {ff} */ x/*{s}ls{
}ls*/(/*{*{*/)/* {ha-ha-ha} */
/*

it's a function

*/
{
  return 'x';
// }
}
/*
*/

indexOflastIndexOf

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' 
"
*/

使用:rm comments from js source

答案 4 :(得分: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

”     Soluçãopopostapelo Paulo Torres no grupo A.P.D.A.没有facebook。

答案 5 :(得分:0)

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

答案 6 :(得分:0)

您可以尝试以下功能:

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

答案 7 :(得分:-1)

试试这个:

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

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

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