function.toString()有哪些实际用途?

时间:2009-08-31 07:41:38

标签: javascript

我在JavaScript中注意到,如果您定义一个函数,比如myfunction(),然后调用myfunction.toString(),您将获得该函数的源文本。这有什么有趣的/现实世界的用途吗?

16 个答案:

答案 0 :(得分:14)

好吧,您可以使用它轻松重新定义函数:

function x() { alert('asdf'); }
eval(x.toString().replace('asdf','hello'));
x();

这将提醒字符串“hello”而不是字符串“asdf”。

这可能很有用。另一方面,由于难以维护代码,自修改代码常常不受欢迎......

答案 1 :(得分:11)

这是一个老问题,但这是我的2美分。

使用node.js,这对于在服务器端创建函数非常有用,然后将这些函数嵌入到页面中并发送到客户端。

例如,dot.js模板引擎首先将模板编译为函数,然后执行该函数以生成HTML代码。

例如:

var compiled = dot.compile("<h1>{{=it.header}}</h1>");
var html_output = compiled({header: "hello world"});

因此,如果我们想在客户端中使用模板而不需要每个客户端首先编译它们,我们可以为它们提供一个包含评估结果的页面:

"var compiled = " + dot.compile("<h1>{{=it.header}}</h1>").toString();
然后

将提供一个“编译”函数客户端,用于编译数据,例如从ajax请求发送到HTML客户端的数据。

答案 2 :(得分:8)

我用它来自动生成函数的命名参数版本。例如,如果您有一个功能

function f(a, b, c) {
    return a * b + c;
}

您可以从f.toString()中提取参数名称并使用它来生成一个可以像这样调用的函数:

namedParametersF({ a: 2, b: 3, c: 4}); // f(2, 3, 4);

以下是这个想法的实现:

// Get an array of parameter names from a function
Function.parameters = function(f) {
    // Find the parameter list in f.toString()
    var m = /function[^\(]*\(([^\)]*)\)/.exec(f.toString());
    if (!m) {
        throw new TypeError("Invalid function in parameters");
    }

    var params = m[1].split(',');
    for (var i = 0; i < params.length; i++) {
        // trim possible spaces
        params[i] = params[i].replace(/^\s*|\s*$/g, '');
    }
    return params;
};

// Convert f to a function that accepts named parameters
Function.withNamedParameters = function(f) {
    var params = Function.parameters(f);
    return function(args) {
        var argsArray = new Array(params.length);
        for (var i = 0; i < params.length; i++) {
            argsArray[i] = args[params[i]];
        }
        return f.apply(this, argsArray);
    };
};

我有一个稍微灵活一点的实现,可以在GitHub上转向另一个方向(Function.withPositionalParameters):http://gist.github.com/132782

答案 3 :(得分:7)

我认为这主要用于调试目的......

答案 4 :(得分:4)

详细阐述idea raised above by James Westgate,这是一个使用toString()创建,调度和发布的例子。接收网络工作者:

/*
 * @param fun the function to carry out in the web worker
 * @param mes the message to send to the web worker
 * @param com the function to do on completion
 * creates, dispatches & receives a web worker
 */
function wor(fun, mes, com) {
   var wor = new Worker(URL.createObjectURL(new Blob([
         'self.onmessage = ' + fun.toString()], {
         type: 'application/javascript'
   })));       
   wor.postMessage(mes);
   wor.onmessage = com;
}

通过将函数转换为字符串,我们可以使用它来在对象URL中创建一个函数,然后对其进行解析和解析。在接收数据时执行。

答案 5 :(得分:3)

一个真实世界的例子在Prototype中,它使用它来确定子类中方法的参数名称,以查看它是否应该执行其特殊的superclass handling内容(涉及特殊参数) $super)。

答案 6 :(得分:3)

CouchDb的视图定义将mapreduce作为字符串。使用function.toString,您可以将这些函数编写为正确的函数(因此IDE /语法检查器可以帮助您),然后在插入时将它们转换为字符串。

答案 7 :(得分:3)

Angular JS使用此模式注入其内置服务。您需要做的就是使用服务名称(以“$”为前缀)作为函数的参数 - 例如:“$ http”。

See the exact usage on Github.

答案 8 :(得分:3)

Javascript源代码中的多行字符串。

this blog post by @tjanczuk中所述,Javascript中的一个巨大不便之处是多行字符串。但您可以利用.toString()和多行注释(/* ... */)的语法来生成相同的结果。

使用following function

function uncomment(fn){
  return fn.toString().split(/\/\*\n|\n\*\//g).slice(1,-1).join();
};

...然后您可以按以下格式传递多行注释:

var superString = uncomment(function(){/*
String line 1
String line 2
String line 3
*/});

在原始文章中,注意到Function.toString()的行为不是标准化的,因此是实现离散的 - 推荐的用法是针对Node.js(可以依赖V8解释器);但是,a Fiddle I wrote seems to work on every browser I have available to me(Chrome 27,Firefox 21,Opera 12,Internet Explorer 8)。

答案 9 :(得分:2)

我相信Visual Studio的Intellisense使用它来查找和解析任何此类记录的函数的可选XML Code Comments,如下所示:

function areaFunction(radiusParam)
{
    /// <summary>Determines the area of a cicle based on a radius parameter.</summary>
    /// <param name="radius" type="Number">The radius of the circle.</param>
    /// <returns type="Number">Returns a number that represents the area.</returns>
    var areaVal;
    areaVal = Math.PI * radiusParam * radiusParam;
    return areaVal;
}

可以想象,您可以在运行时自己解析这个问题,随意提供文档或补充未处理异常的详细信息。

答案 10 :(得分:1)

在多窗口Web应用程序中,如果您需要在Windows之间共享一个函数以便稍后执行,但不能保证该函数的所有者(它所定义的窗口)将是在执行时生效,您可以使用toString()序列化该函数,将其存储到相关窗口,并在以后的执行时间/时间调用eval()。当然,使用eval()有自己的瑕疵,但这似乎是一个合法的用例(我们需要重新调用脚本解析引擎以将序列化函数转换回可执行代码)。

这是在这种情况下唯一没有获得访问被拒绝错误的确定方法。这里的问题是执行上下文现在变成了我们从eval()调用的窗口,而不是函数最初定义的范围,因此必须注意不要依赖函数之外的变量&#39;直接范围。

答案 11 :(得分:0)

除了将函数的内容作为字符串获取,或确保您正在使用的任何字符的类型是一个字符串(用于非强制性比较)之外,请查看可选项可以使用的基数参数。

radix 可选。指定用于将数值转换为字符串的基数。该值仅用于数字。

var a = 16;
a.toString(2)    // returns "10000"
a.toString(4)    // returns "100"
a.toString(8)    // returns "20"
a.toString(16)   // returns "10"
a.toString(32)   // returns "g"

以下示例说明了使用带有radix参数的toString方法。下面显示的函数的返回值是基数转换表。

function CreateRadixTable (){
   var s, s1, s2, s3, x;                    //Declare variables.
   s = "Hex    Dec   Bin \n";               //Create table heading.
   for (x = 0; x < 16; x++)                 //Establish size of table
   {                                        // in terms of number of
      switch(x)                             // values shown.
      {                                     //Set intercolumn spacing.
         case 0 : 
            s1 = "      ";
            s2 = "    ";
            s3 = "   ";
            break;
         case 1 :
            s1 = "      ";
            s2 = "    ";
            s3 = "   ";
            break;
         case 2 :
            s3 = "  ";
            break;
         case 3 : 
            s3 = "  ";
            break;
         case 4 : 
            s3 = " ";
            break;
         case 5 :
            s3 = " ";
            break;
         case 6 : 
            s3 = " ";
            break;
         case 7 : 
            s3 = " ";
            break;
         case 8 :
            s3 = "" ;
            break;
         case 9 :
            s3 = "";
            break;
         default: 
            s1 = "     ";
            s2 = "";
            s3 = "    ";
      }                                     //Convert to hex, decimal & binary.
      s += " " + x.toString(16) + s1 + x.toString(10)
      s +=  s2 + s3 + x.toString(2)+ "\n";

   }
   return(s);                               //Return entire radix table.
}

答案 12 :(得分:0)

可以用作编写Web Workers的方法,而无需将函数放在单独的文件中。

答案 13 :(得分:0)

您可以利用函数字符串化在生成的页面中包含一个函数,并在源代码中突出显示函数。 我也用CoffeeScript完成了这个,用函数编写并突出显示为CoffeeScript,但是因为它是...而被视为JavaScript函数。或者因为在编译CoffeeScript的其余部分时将其编译为一个。

See this on github:

        error_handling = ->
            d = document.createElement "div"
            d.className = "error bubble script-error"
            window.onerror = (error)->
                document.body.appendChild d
                d.style.position = "absolute"
                d.style.borderRadius = d.style.padding = 
                d.style.bottom = d.style.right = "5px"
                d.innerText = d.textContent = error

        body += """
            <script>~#{error_handling}()</script>
            <style>
                .error {
                    color: red;
                }
                .error.bubble {
                    background: rgba(255, 0, 0, 0.8);
                    color: white;
                }
                body {
                    font-family: Helvetica, sans-serif;
                }
            </style>
        """

答案 14 :(得分:0)

断言arg不为空

exports.warnNull = function() {
  var func = arguments.callee.caller
  var args = func.toString().match(/function\s*\w*\((.*?)\)\s*/)[1].split(',').map(Function.prototype.call.bind(String.prototype.trim))
  var params = Array.prototype.slice.call(arguments)
  for (var i = 0; i < params.length; i ++) {
    if (!params[i]) {
      console.warn(gutil.colors.yellow('缺少变量 : ' + args[i]))
    }
  }
}

wrap long String

exports.controller = function(){
/*
app.controller('{{ controllerName }}', function({{ injects }}) {
  // ...
})
*/
}.toString().slice(16, -4)

答案 15 :(得分:0)

toString是一种序列化方法。在某些情况下,我们需要将功能逻辑存储到数据库或通过互联网传输的存储中。也是描述“如何做某事”的一种数据。