在 Internet Explorer 中实现 Mozilla 的 toSource() 方法

IT技术 javascript
2021-03-14 02:29:45

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

6个回答

请考虑以下事项:(使用 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#]

和“going 'infinite'”消息,其中遵循 JSON 的 stackoverflow 递归离题。

这些示例强调了从 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,无穷大,NaN,void(0), 
                        函数,数组,对象,未定义]

    源():
    [JSON,数学,空,无穷大,NaN,(空0), 
        function Function() {[本机代码]}, function Array() {[本机代码]}, 
            function Object() {[本机代码]}, (void 0)]

    JSON:
    [{},{},null,null,null,null,null,null,null,null]

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

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

  • 代码转换的重复是否会停顿到静态?
  • obj.toSource() == eval(eval(eval(eval(obj.toSource()).toSource()).toSource()).toSource()?
  • 考虑 obj == eval(obj.toSource()) 是否有意义?
  • 撤消转换是否不仅会导致类似的对象,还会导致相同的对象?
    在克隆操作对象时,这是一个具有深远影响的问题。

还有很多很多……

请注意,当 obj 包含已执行的代码对象(例如 (new Function ... )()!)时,上述问题具有额外的意义。

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

相反,如果 JSON 足以满足 OP 的需要,即不需要反编译函数、允许循环引用等。
2021-04-30 02:29:45

如果您需要使用循环引用序列化对象,您可以使用 Douglas Crockford 对 JSON 对象的 cycle.js 扩展,可从https://github.com/douglascrockford/JSON-js 获得这与 toSource() 非常相似,虽然它不会序列化函数(但可能适用于使用函数的 toString 方法)。

你可以这样做:

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也许将其作为免费功能实现会更好。
2021-04-18 02:29:45
修改 Object 原型并不是一个好主意。此外,字符串类型需要的不仅仅是 \" 转义。它还需要转义 \t\n\r 等。
2021-05-03 02:29:45
修改对象原型是一个非常好的主意,前提是您知道如何在 JavaScript 中编码并且不使用在您这样做时明确选择被破坏的库(如 jQuery)(为了提高速度)。
2021-05-11 02:29:45

为了更进一步:当你发送一些东西 - 要处理 - 接收者必须得到它并且能够处理它。因此,下一段代码将发挥作用 - 改编自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. 如果您拥有所有正在传输的代码:请随意使用它(尽管它也有缺点)。如果你不知道来源来自哪里:这是一个禁忌。