最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Javascript object get code as string - Stack Overflow

programmeradmin1浏览0评论

First off, I am sorry if this is a duplicate, but every time I googled for 'object' and 'code' I got tutorial pages.

I want to know if there is any easy way to get the code associated with an object. Something like

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

I want to be able to view the code, modify it and reload the function, all from within the browser. I wanted to know if there was some way to do this, or if I have to prime the pump by doing something like this:

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

then every time the user loads up the text editor to view this.code I connect the onchange to update this.code.

EDIT

turns out yankee suggested a simple solution to this

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

but in my implementation the variable 'x' can be a function (actually a complicated object with variables, functions and sub objects which I mix in via a call to dojo.mixin), so what I really want is to know the code when instantiated, something like so

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

but, as most of you already know, all that gets output is something like "Object". I have almost found a way around this, by putting the initialization in a function like so

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*/);
}"

but that is confusing, and then I have to go in and start parsing the string which I do not want to do.

EDIT: The reason I ask all of this is b/c I want to make code that is both dynamically executable and highly modular. I am dealing with the canvas. I want the user to be able to click on a, for example, rectangle, view its code, and modify and then load/execute it. I have a series of rules but basically I have a shape class and everything that defines that shape (color, transparency, fills, strokes...) has to get passed as a parameter to the object cosntructor, something like:

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

This way the code is automatically modular, I don't have to worry about the color being defined at the top of the page, and then the height being defined half way down the page, and so on. Now the only thing I need is to somehow, pass as a parameter, the entire above string representation of the initialization. I could wrap it in a function and call toString on that, like so

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()
      });
  }

but then there are two problems. 1) I have to manually remove the function wrapper() and trailing } as well as moving every line to the left by one tab. 2) there is no guarantee that a user will remember to include the wrapper function as it is totally unecessary for purposes of drawing. I am trying to think of a way where the wrapper would seem natural, but I can't think of any. But then again I haven't slept in over 30 hours.

First off, I am sorry if this is a duplicate, but every time I googled for 'object' and 'code' I got tutorial pages.

I want to know if there is any easy way to get the code associated with an object. Something like

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

I want to be able to view the code, modify it and reload the function, all from within the browser. I wanted to know if there was some way to do this, or if I have to prime the pump by doing something like this:

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

then every time the user loads up the text editor to view this.code I connect the onchange to update this.code.

EDIT

turns out yankee suggested a simple solution to this

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

but in my implementation the variable 'x' can be a function (actually a complicated object with variables, functions and sub objects which I mix in via a call to dojo.mixin), so what I really want is to know the code when instantiated, something like so

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

but, as most of you already know, all that gets output is something like "Object". I have almost found a way around this, by putting the initialization in a function like so

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*/);
}"

but that is confusing, and then I have to go in and start parsing the string which I do not want to do.

EDIT: The reason I ask all of this is b/c I want to make code that is both dynamically executable and highly modular. I am dealing with the canvas. I want the user to be able to click on a, for example, rectangle, view its code, and modify and then load/execute it. I have a series of rules but basically I have a shape class and everything that defines that shape (color, transparency, fills, strokes...) has to get passed as a parameter to the object cosntructor, something like:

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

This way the code is automatically modular, I don't have to worry about the color being defined at the top of the page, and then the height being defined half way down the page, and so on. Now the only thing I need is to somehow, pass as a parameter, the entire above string representation of the initialization. I could wrap it in a function and call toString on that, like so

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()
      });
  }

but then there are two problems. 1) I have to manually remove the function wrapper() and trailing } as well as moving every line to the left by one tab. 2) there is no guarantee that a user will remember to include the wrapper function as it is totally unecessary for purposes of drawing. I am trying to think of a way where the wrapper would seem natural, but I can't think of any. But then again I haven't slept in over 30 hours.

Share Improve this question edited Apr 24, 2014 at 18:58 tshepang 12.5k25 gold badges97 silver badges139 bronze badges asked Jul 5, 2011 at 13:22 pukpuk 16.8k31 gold badges124 silver badges205 bronze badges 2
  • 1 +1 just for referencing Kaiser Sauze... although I think it is spelled Keyser Söze ;-) – Jason Gennaro Commented Jul 5, 2011 at 13:26
  • @Jason: I can never remember how to spell it, so when I give out my number to the ladies, I go by Rolo Tomasi ;-) – puk Commented Jul 5, 2011 at 14:27
Add a comment  | 

8 Answers 8

Reset to default 22

OK... Reviewing again... I think that's what you want ;-).

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

Refer to code snippet below:

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

a = new A();

console.log(a.constructor.toString());

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

When you do new A(), function A becomes the constructor of object a. Thus, you can reference function A via the constructor property of object a.

Read more about Javascript constructor on MDN.

Edit: added pretty-printing.

You could JSON.stringify() the argument of the constructor, if it is JSON-compatible. Here is a toString() function that builds on this idea, but with a slightly generalized version of JSON.stringify() that accepts stringifying functions:

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

The output is:

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

I can't believe no one suggested this (I apologize if this answer is somewhere in between the lines). I didn't think of it because at the time of development, all my work was clientside. All I really have to do is load the code once with Ajax as javascript. Once it is loaded and an object created, I load it again as a string and assign it to a variable in the object.

Here is another solution that might work (using yankee's example). I am however unsure what happens if A already exists? Perhaps you should do a "delete(A);" before saving it in the storage.

// 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);
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;
//    }

Here is my fiddle for that: http://jsfiddle.net/DanielDZC/vXrQf/

I wouldn't recommend using on a production server, only for testing and debugging, but there is a method named toSource() which returns the source of a function as a String:

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

Outputs:

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

Available on JS Fiddle: http://jsfiddle.net/IQAndreas/dP453/1/

Note that Mozilla has marked this method as non-standard (which if you read the details means "Only works in FireFox").

Sounds like you're looking for Reflection and/or Introspection support. I'm not sure where the other major engines are at in this regards but SpiderMonkey's Parser API was recently referenced in an article on Extension Introspection with Chrome Privileges.

发布评论

评论列表(0)

  1. 暂无评论