tags:

views:

2256

answers:

3

Has anyone implemented Mozilla's Object.toSource() method for Internet Explorer and other non-Gecko browsers? I'm looking for a lightweight way to serialize simple objects into strings.

+5  A: 

If matching the exact serialization format of Firefox is not your aim, you could use one of the JavaScript JSON serialization/deserialization libraries listed at http://json.org. Using a standard scheme like JSON may be better than mimicking the proprietary Gecko format.

Ates Goral
Rather, if JSON is enough for the OP's needs, i.e. no need to decompile functions, allow circular references, etc.
Nickolay
A: 

You could do something like this:

Object.prototype.getSource = function() {
    var output = [], temp;
    for (var i in this) {
        if (this.hasOwnProperty(i)) {
            temp = i + ":";
            switch (typeof this[i]) {
                case "object" :
                    temp += this[i].getSource();
                    break;
                case "string" :
                    temp += "\"" + this[i] + "\"";    // add in some code to escape quotes
                    break;
                default :
                    temp += this[i];
            }
            output.push(temp);
        }
    }
    return "{" + output.join() + "}";
}
nickf
I'm not a JavaScript expert, but Object.prototype is verboten! See: http://erik.eae.net/archives/2005/06/06/22.13.54/ Maybe it's better to implement this as a free function.
jk
Its not a good idea to modify the Object prototype. Also a string type will need more than just \" escaping. It will need escaping of \t\n\r etc.
AnthonyWJones
A: 

See also JavaScript data formatting/pretty printer. I think the routine exports in valid JS format, so it can be eval to get it back.

[EDIT] Actually, not! It is OK for quick dump but not for real serialization. I improved it, result below:

function SerializeObject(obj, indentValue)
{
  var hexDigits = "0123456789ABCDEF";
  function ToHex(d)
  {
    return hexDigits[d >> 8] + hexDigits[d & 0x0F];
  }
  function Escape(string)
  {
    return string.replace(/[\x00-\x1F'\\]/g,
        function (x)
        {
          if (x == "'" || x == "\\") return "\\" + x;
          return "\\x" + ToHex(String.charCodeAt(x, 0));
        })
  }

  var indent;
  if (indentValue == null)
  {
    indentValue = "";
    indent = ""; // or " "
  }
  else
  {
    indent = "\n";
  }
  return GetObject(obj, indent).replace(/,$/, "");

  function GetObject(obj, indent)
  {
    if (typeof obj == 'string')
    {
      return "'" + Escape(obj) + "',";
    }
    if (obj instanceof Array)
    {
      result = indent + "[";
      for (var i = 0; i < obj.length; i++)
      {
        result += indent + indentValue +
            GetObject(obj[i], indent + indentValue);
      }
      result += indent + "],";
      return result;
    }
    var result = "";
    if (typeof obj == 'object')
    {
      result += indent + "{";
      for (var property in obj)
      {
        result += indent + indentValue + "'" +
            Escape(property) + "' : " +
            GetObject(obj[property], indent + indentValue);
      }
      result += indent + "},";
    }
    else
    {
      result += obj + ",";
    }
    return result.replace(/,(\n?\s*)([\]}])/g, "$1$2");
  }
}

indentValue can be null, "", " ", "\t" or whatever. If null, no indentation, output a rather compact result (could use less spaces...).

I could use an array to stack the results then join them, but unless you have giant objects, string concatenation should be good enough...
Also doesn't handle cyclic references...

PhiLho