【问题标题】:Implementing Mozilla's toSource() method in Internet Explorer在 Internet Explorer 中实现 Mozilla 的 toSource() 方法
【发布时间】:2010-09-15 08:16:24
【问题描述】:

是否有人为 Internet Explorer 和其他非 Gecko 浏览器实现了 Mozilla 的 Object.toSource() 方法?我正在寻找一种将简单对象序列化为字符串的轻量级方法。

【问题讨论】:

    标签: javascript


    【解决方案1】:

    如果匹配 Firefox 的确切序列化格式不是您的目标,您可以使用http://json.org 中列出的 JavaScript JSON 序列化/反序列化库之一。使用像 JSON 这样的标准方案可能比模仿专有的 Gecko 格式更好。

    【讨论】:

    • 相反,如果 JSON 足以满足 OP 的需求,即不需要反编译函数、允许循环引用等。
    【解决方案2】:

    你可以这样做:

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

    【讨论】:

    • 我不是 JavaScript 专家,但 Object.prototype 已被禁止!请参阅:erik.eae.net/archives/2005/06/06/22.13.54 也许最好将其实现为免费功能。
    • 修改Object原型不是个好主意。此外,字符串类型需要的不仅仅是 \" 转义。它需要转义 \t\n\r 等。
    • 修改 Object 原型是一个非常好的主意,前提是您知道如何在 JavaScript 中编写代码并且没有使用明确选择破坏的库(如 jQuery)(为了提高速度)。
    【解决方案3】:

    另见JavaScript data formatting/pretty printer。我认为例程以有效的 JS 格式导出,因此可以通过 eval 将其取回。

    [编辑] 实际上,不是!快速转储可以,但不能用于真正的序列化。 我改进了它,结果如下:

    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 可以为 null、""、""、"\t" 或其他任何值。如果为 null,则不缩进,输出相当紧凑的结果(可以使用更少的空格...)。

    我可以使用一个数组来堆叠结果然后加入它们,但除非你有巨大的对象,否则字符串连接应该足够好......
    也不处理循环引用...

    【讨论】:

      【解决方案4】:

      如果您需要使用循环引用对对象进行序列化,您可以使用 Douglas Crockford 对 JSON 对象的 cycle.js 扩展,地址为https://github.com/douglascrockford/JSON-js。这很像 toSource(),虽然它不会序列化函数(但可能适合使用函数的 toString 方法)。

      【讨论】:

        【解决方案5】:

        考虑以下几点:(使用 FireFox 3.6 时)

        javascript:
          x=function(){alert('caveat compter')};
          alert(['JSON:\t',JSON.stringify(x),'\n\ntoSource():\t',x.toSource()].join(''));
        

        显示:

        JSON:

        toSource(): (function () {alert("caveat compter");})

        甚至:

        javascript:
        x=[];x[3]=x;
        alert('toSource():\t'+x.toSource());
        alert('JSON can not handle this at all and goes "infinite".');
        alert('JSON:\n'+JSON.stringify(x));
        

        显示:

        toSource(): #1=[, , , #1#]

        以及跟随 JSON 的 stackoverflow 递归题外话的“going 'infinite'”消息。

        这些示例强调了从 toSource() 呈现的 JSON 表示中明确排除的表达式的微妙之处。

        编写一个程序来复制所有情况下的相同结果并不容易,就像 Gecko toSource() 原语一样,它非常强大。

        以下是复制 toSource() 功能的程序必须成功处理的一些“移动目标”:

        javascript:
        function render(title,src){ (function(objRA){
            alert([ title, src,
                '\ntoSource():',objRA.toSource(),
                '\nJSON:',JSON.stringify(objRA)     ].join('\n'));
            })(eval(src));
        }
        render('Simple Raw Object source code:',
            '[new Array, new Object, new Number, new String, ' +
                'new Boolean, new Date, new RegExp, new Function]'  );
        
        render( 'Literal Instances source code:',
            '[ [], 1, true, {}, "", /./, new Date(), function(){} ]'    );
        
        render( 'some predefined entities:',
            '[JSON, Math, null, Infinity, NaN, ' +
                'void(0), Function, Array, Object, undefined]'      );
        

        显示:

        简单原始对象源代码: [新数组,新对象,新数字,新字符串, 新布尔值、新日期、新正则表达式、新函数] 源(): [[], {}, (new Number(0)), (new String("")), (new Boolean(false)), (new Date(1302637995772)), /(?:)/, (函数匿名(){})] JSON: [[],{},0,"",false,"2011-04-12T19:53:15.772Z",{},null]

        然后显示:

        文字实例源代码: [ [], 1, true, {}, "", /./, new Date(), function(){} ] 源(): [[], 1, true, {}, "", /./, (new Date(1302638514097)), (function () {})] JSON: [[],1,true,{},"",{},"2011-04-12T20:01:54.097Z",null]

        最后:

        一些预定义的实体: [JSON, 数学, null, Infinity, NaN, void(0), 函数,数组,对象,未定义] 源(): [JSON, 数学, null, Infinity, NaN, (void 0), 函数函数(){[本机代码]},函数数组(){[本机代码]}, function Object() {[native code]}, (void 0)] JSON: [{},{},null,null,null,null,null,null,null,null]

        如果翻译是“要使用的”,则前面的分析很重要,或者如果需要简单的良性人类消费来查看对象的内部结构,则前面的分析很重要。一个主要的 JSON 特性,作为一种表示,是在环境之间传输一些“要使用”的结构化信息。

        toSource() 函数的质量是影响程序的指称语义的一个因素,但不限于:
        往返计算、最小不动点属性和反函数。

        • 是否重复代码转换 静止到静止状态?
        • obj.toSource() 是否 == eval(eval(eval(obj.toSource()).toSource()).toSource()).toSource()?
        • 考虑是否有意义 是否 obj == eval(obj.toSource())?
        • 撤消转换会导致,而不是 只是一个类似的对象,但是一个 一模一样吗?
          这是一个加载 具有深远意义的问题 克隆操作对象时。

        还有很多很多...

        请注意,当 obj 包含已执行的代码对象时,上述问题会变得更加重要,例如 (new Function ... )()!

        【讨论】:

          【解决方案6】:

          您不必使用toSource();将要序列化的代码包装在一个返回 JSON 结构的函数中,并改用 function#toString()

          var serialized = function () {
              return {
                  n: 8,
                  o: null,
                  b: true,
                  s: 'text',
                  a: ['a', 'b', 'c'],
                  f: function () {
                      alert('!')
                  }
              }
          };
          serialized.toString();
          

          查看live demo on jsFiddle

          【讨论】:

            【解决方案7】:

            为了更进一步:当您发送某些东西时 - 要处理 - 接收者必须得到它并且能够处理它。因此,下一段代码将起到作用 - 改编自 Eliran Malka 的上一个答案。

            // SENDER IS WRAPPING OBJECT TO BE SENT AS STRING
            // object to serialize
            var s1 = function (str) {
                return {
                    n: 8,
                    o: null,
                    b: true,
                    s: 'text',
                    a: ['a', 'b', 'c'],
                    f: function () {
                        alert(str)
                    }
                }
            };
            // test
            s1("this function call works!").f();
            // serialized object; for newbies: object is now a string and can be sent ;)
            var code = s1.toString();
            
            // RECEIVER KNOWS A WRAPPED OBJECT IS COMING IN
            // you have to assign your wrapped object to somevar
            eval('var s2  = ' + code);
            // and then you can test somevar again
            s2("this also works!").f();
            

            注意eval 的使用。如果您拥有所有正在传输的代码:请随意使用它(尽管它也可能有缺点)。如果您不知道来源来自哪里:这是不行的。

            【讨论】:

              【解决方案8】:

              还没有人提到它,所以我要指出的是,Mozilla 的 Object.toSource https://github.com/oliver-moran/toSource.js 有一个 polyfill 可用

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2011-12-20
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-04-21
                相关资源
                最近更新 更多