【问题标题】:Javascript object get code as stringJavascript 对象将代码作为字符串获取
【发布时间】:2011-09-28 19:49:51
【问题描述】:

首先,如果这是重复的,我很抱歉,但每次我搜索“对象”和“代码”时,我都会得到教程页面。

我想知道是否有任何简单的方法可以获取与对象关联的代码。类似的东西

function A(){
  this.name = 'Kaiser Sauze';
}
a = new A();
console.log(a.displayCode());
//OUTPUT
"function A(){ this.name = 'Kaiser Sauze';}"

我希望能够在浏览器中查看代码、修改代码并重新加载函数。我想知道是否有某种方法可以做到这一点,或者我是否必须通过执行以下操作来启动泵:

function A(){
  this.name = 'Kaiser Sauze';
  this.code = "function A(){ this.name = 'Kaiser Sauze';}"
}

然后每次用户加载文本编辑器以查看 this.code 时,我都会连接 onchange 以更新 this.code

编辑

原来 yankee 提出了一个简单的解决方案

function A(x){
  this.x = x ;
}
console.log(A.toString());
//OUTPUT
"function A(x){
  this.x = x ;
}"

但在我的实现中,变量“x”可以是一个函数(实际上是一个复杂的对象,其中包含我通过调用 dojo.mixin 混合的变量、函数和子对象),所以我真正想要的是知道实例化时的代码,类似这样

function A(x){
  this.x = x ;
}
var a = new A(function(){/*DO SOMETHING*/);
console.log(a.toString());
//OUTPUT
"var a = new A(function(){/*DO SOMETHING*/);"

但是,正如你们大多数人已经知道的那样,所有获得输出的东西都类似于“对象”。通过将初始化放在这样的函数中,我几乎找到了解决方法

function A(x){
  this.x = x ;
}
function _A(){
  var a = new A(function(){/*DO SOMETHING*/);
}
console.log(_A.toString());
//OUTPUT
"function _A(){
  var a = new A(function(){/*DO SOMETHING*/);
}"

但这很混乱,然后我必须进入并开始解析我不想做的字符串。

编辑:我问这一切的原因是 b/c 我想制作既可动态执行又可高度模块化的代码。我正在处理画布。我希望用户能够点击一个矩形,查看它的代码,修改然后加载/执行它。我有一系列规则,但基本上我有一个形状类,并且定义该形状的所有内容(颜色、透明度、填充、笔触......)都必须作为参数传递给对象构造函数,例如:

rect = new Shape({color : 'rgba(0,0,0,1)' , 
  x : 0 , 
  y : 0 , 
  w : 100 , 
  h : 100 ,
  draw : function() {ctx.fillStyle = this.color;
    ctx.fillRect(this.x,this.y,this.w,this.h);
  }
});

这样代码是自动模块化的,我不必担心在页面顶部定义颜色,然后在页面中间定义高度,等等。现在我唯一需要做的就是以某种方式将初始化的整个上述字符串表示形式作为参数传递。我可以将它包装在一个函数中并在其上调用 toString,就像这样

function wrapper(){
  rect = new Shape({color : 'rgba(0,0,0,1)' , 
        x : 0 , 
        y : 0 , 
        w : 100 , 
        h : 100 ,
        draw : function() {ctx.fillStyle = this.color;
          ctx.fillRect(this.x,this.y,this.w,this.h);
        },
        code : wrapper.toString()
      });
  }

但是有两个问题。 1) 我必须手动删除function wrapper() 和尾随},并将每一行向左移动一个标签。 2) 不能保证用户会记得包含包装函数,因为它对于绘图是完全不必要的。我试图想出一种包装看起来很自然的方法,但我想不出任何方法。但话说回来,我已经超过 30 个小时没有睡觉了。

【问题讨论】:

  • +1 只是为了引用 Kaiser Sauze ......虽然我认为它的拼写是 Keyser Söze ;-)
  • @Jason:我不记得怎么拼了,所以当我把我的号码给女士们的时候,我会选择 Rolo Tomasi ;-)

标签: javascript object tostring


【解决方案1】:

好的...再次审核...我认为这就是您想要的 ;-)。

>>> function A() {this.name ="foo";}
undefined
>>> A.toString()
"function A() {this.name ="foo";}"

【讨论】:

  • 哇,真的超级酷。我通常抨击 Javascript 完全不如 Python,但在这种情况下,它赢了。不幸的是,这不是我想要的。我现在意识到这是一个愚蠢的问题 b/c 对象没有字符串表示。我要么将所有内容重新实现为一个类,要么找到另一种方法来实现它。不过还是谢谢。
  • 我也可以将对象初始化放在一个函数中,然后在上面调用字符串。
  • 我想我会编辑问题以更新所有感兴趣的人。另外,由于某种原因,当我做 AT yankee 时,它​​并没有出现。
  • 回复某人时,您应该使用“at”符号。就像用户 AT hotmail.com。但是当我尝试写 AT yankee 时,最后两次都没有用
【解决方案2】:
function dumpObject(obj) 
{     
    var output = "";     
    for (var i in obj) 
    {         
        var msg = i + "= " + obj[i];         
        output += msg + "\n";     
    }     
    return output; 
} 

var myObject = {
    myName: 'Daniel',

    get_name: function()
    {
        return this.myName;
    }
}

alert( dumpObject(myObject) );
//this will output:
//
//    myName= Daniel
//    get_name=function()
//    {
//        return this.myName;
//    }

这是我的小提琴: http://jsfiddle.net/DanielDZC/vXrQf/

【讨论】:

  • 我不认为这就是我要找的东西,我想要的是代码,而不仅仅是属性。
  • 这将显示函数、属性等,但它们中的每一个都是分开的。您可以对其进行调整,以便每个循环都将内容添加到一个字符串而不是警告它。事实上让我改变它......
  • 丹尼尔,谢谢你的 jsfiddle。它绝对清除了一切:)
  • 我知道它是如何工作的,但我想保留用户编写代码的方式(不同的间距、标签大小......)我将只使用文本区域并更新代码并保存副本代码中的代码(如果我自己可以这么说的话,非常漂亮)
  • 嘿丹尼尔,我只是想感谢你提供的代码。在获取对象“代码”时,我将采用您的方法,在获取类/其他代码时,我将采用 psema4 的方法(如下)。本质上,我将拥有三个选项卡,一个用于脚本中的所有代码,另一个用于类,最后一个用于对象(不可修改)。由于我问的是关于对象而不是类的问题,因此我会将您的问题标记为答案
【解决方案3】:

编辑:添加了漂亮的打印。

您可以JSON.stringify() 构造函数的参数,如果它与 JSON 兼容。这是一个基于这个想法的toString() 函数,但有一个稍微通用的JSON.stringify() 版本,它接受字符串化函数:

function Shape(x){
    this.x = x;
}
Shape.prototype.toString = function() {
    function stringify(data, prefix) {
        function unicode_escape(c) {
            var s = c.charCodeAt(0).toString(16);
            while (s.length < 4) s = "0" + s;
            return "\\u" + s;
        }
        if (!prefix) prefix = "";
        switch (typeof data) {
            case "object":  // object, array or null
                if (data == null) return "null";
                var i, pieces = [], before, after;
                var indent = prefix + "    ";
                if (data instanceof Array) {
                    for (i = 0; i < data.length; i++)
                        pieces.push(stringify(data[i], indent));
                    before = "[\n";
                    after = "]";
                }
                else {
                    for (i in data)
                        pieces.push(i + ": " + stringify(data[i], indent));
                    before = "{\n";
                    after = "}";
                }
                return before + indent
                       + pieces.join(",\n" + indent)
                       + "\n" + prefix + after;
            case "string":
                data = data.replace(/\\/g, "\\\\").replace(/"/g, '\\"')
                           .replace(/\n/g, "\\n").replace(/\r/g, "\\r")
                           .replace(/\t/g, "\\t")
                           .replace(/[\x00-\x19]/g, unicode_escape);
                return '"' + data + '"';
            default:
                return String(data).replace(/\n/g, "\n" + prefix);
        }
    }
    return "new Shape(" + stringify(this.x) + ")";
};

var rect = new Shape({color : 'rgba(0,0,0,1)' , 
  x : 0 , 
  y : 0 , 
  w : 100 , 
  h : 100 ,
  draw : function() {ctx.fillStyle = this.color;
    ctx.fillRect(this.x,this.y,this.w,this.h);
  }
});
console.log(rect.toString());

输出是:

new Shape({
    color: "rgba(0,0,0,1)",
    x: 0,
    y: 0,
    w: 100,
    h: 100,
    draw: function() {
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.w, this.h);
    }
})

【讨论】:

  • 哇,我没想到会有这么多答案。或许我应该先解释一下为什么我会问这个问题。我会再次编辑。
  • 我再次编辑了我的问题。我解释了为什么我需要它,以及为什么我不仅需要对象的结构,还需要代码本身的结构。因此,出于美学原因,我需要制表符、空格和换行符。否则用户会输入一些东西,保存它,然后当他们重新打开它时,突然间所有的代码都被压缩成一行了
  • 没有办法恢复原始的空格、制表符和换行符,除非首先将代码保存为字符串(这实际上可能是最容易遵循的路径)。我编辑了我的答案以提高输出的美感。但是,这个toString() 实际上是用我的缩进样式重新缩进(四个空格缩进,':' 之前没有空格......),尽管代码最初是使用您的样式输入的。您显然可以编辑 toString() 以适合您的风格。
  • 我可能弄错了,但是如果您在函数上调用 toString(),它将为您提供实现的精确副本,包括空格/制表符
  • 我不确定是否指定了此行为,它可能与实现有关。至少 Firefox 3.6 和 Qt 4.5 (QtScript) 提供了重新格式化的函数版本。
【解决方案4】:

听起来您正在寻找反射和/或内省支持。我不确定其他主要引擎在这方面处于什么位置,但最近在 Extension Introspection with Chrome Privileges 上的一篇文章中引用了 SpiderMonkey 的 Parser API

【讨论】:

  • 我回避使用解析器,因为我对它们几乎没有经验,但我可能不得不开始。我在想的另一件事是将每个函数存储为一个文件,然后将它们加载到 index.html 中(或者为了提高效率,只要其中一个子文件被更改并且只在 index.html 中加载它,就可以将它们合并到一个单独的 .js 文件中),然后让该文件生成的每个对象都知道文件路径。
  • 我的 AT(@) 标志没有出现是什么原因?我无法再以@user(@user)的形式回复特定用户。是语法改变了,还是我不小心改变了我的设置?例如,我尝试使用“@psema4”开始我之前的评论,但在那里我看不到它
  • 感谢 psema4 的链接。我将把它用于非对象部分(即类和整个脚本)
【解决方案5】:

我不敢相信没有人提出这个建议(如果这个答案介于两行之间,我深表歉意)。我没有想到,因为在开发时,我所有的工作都是客户端。我真正需要做的就是使用 Ajax 作为 javascript 加载代码一次。加载并创建对象后,我将其作为字符串再次加载并将其分配给对象中的变量。

【讨论】:

    【解决方案6】:

    这是另一种可能有效的解决方案(使用 yankee 的示例)。但是,我不确定如果 A 已经存在会发生什么?也许你应该做一个“删除(A);”在将其保存到存储之前。

    // Create A
    // function A() {this.name = "foo";}
    
    var x = 'function A() {this.name = "foo";}'; // Store function to variable using A.toString();
    
    // Save x in storage
    
    // -- Page reload --
    
    // Load and eval x from storage
    eval(x);
    
    var a = new A(); // Use A
    alert(a.name);
    

    【讨论】:

      【解决方案7】:

      我不建议在生产服务器上使用,仅用于测试和调试,但 there is a method named toSource() 将函数的源作为字符串返回:

      function add(a, b) {
          return a + b;
      }
      console.log(add.toSource());
      

      输出:

      function add(a, b) { return a + b; }
      

      在 JS Fiddle 上可用:http://jsfiddle.net/IQAndreas/dP453/1/

      请注意,Mozilla 已将此方法标记为非标准(如果您read the details 表示“仅适用于 FireFox”)。

      【讨论】:

        【解决方案8】:

        参考下面的代码sn-p:

        function A() {
          this.name = 'Kaiser Sauze';
        }
        
        a = new A();
        
        console.log(a.constructor.toString());
        
        // output
        // "function A(){
        //   this.name = 'Kaiser Sauze';
        // }"

        当您执行new A() 时,function A 成为对象a 的构造函数。因此,您可以通过对象aconstructor 属性引用function A

        Read more about Javascript constructor on MDN.

        【讨论】:

          猜你喜欢
          • 2015-10-26
          • 1970-01-01
          • 1970-01-01
          • 2011-10-12
          • 2016-11-05
          • 2011-11-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多