2

使用JSON.stringifyandJSON.parse序列化和反序列化对象有一些微妙的问题,例如日期对象被序列化为字符串,然后在另一端作为字符串而不是日期对象出现。我已经尝试使用postMessage具有产生 1:1 结果的好处的替代方法,但我担心其他处理程序会忽略消息。我考虑过编写自己的序列化器/反序列化器,但更喜欢本机浏览器功能。

有没有办法postMessage像序列化器一样使用,而不必担心被窃听?

注意:我不关心使用开发工具窃听。我的应用程序正在加载类似模块的插件,我想确保这些插件无法窃听其他模块的消息。

4

3 回答 3

6

JSON.stringify您可以向and提供自定义 JSON 解析器/字符串化器JSON.parse

var serialized = JSON.stringify(obj, /*func*/replacer);
var deserialized = JSON.parse(serialized, /*func*/reviver);

除了自定义 reviver 之外,您还可以toJSON在将要序列化的对象上定义一个方法。此方法接收一个参数:数组中键的名称索引、对象中的属性名称(如果适用)。

// Examples of a serializing a function
var dummyFunction = function() {return 'hey';};

Function.prototype.toJSON = function(key) {
    'use strict';
    return this.toString();
};
JSON.stringify(dummyFunction);
// Method 2:
var replacer = function(/*string*/key, /*any*/value, /*boolean*/pretty_print) {
    if (typeof value == 'function') return value.toString();
    return value;
};
JSON.stringify(dummyFunction, replacer);
// >>> "function () {\n    return \"hey\";\n}"
// Result of the previous, stored in a variable
var result =  '"function () {\\n    return \\"hey\\";\\n}"';

// Reviver example
// Note: Just an example. Do not use it without modification in production code,
// Because the pattern can easily be misguided: "function(){}alert('Evil');x={}"
// Even if you do not mind, at least add a try-catch block inside
//   `if (func)`, so that a malformed function does not break the reviver
JSON.parse(result, function(/*string*/key, /*string*/value) {
    var func = /^\s*function\s*\(([^)]*)\)\s\{([\S\s]*)}$/.exec(value);
    if (func) {
        // Note: Function( .. ) is equivalent to new Function( .. )
        var args = func[1].match(/[^,\s]+/g); // <-- Parameters
        // Function body:
        if (args === null) args = [func[2]];
        else args.unshift(func[2]);
        return Function.apply(null, args);
    }
    return value;
});

这是本机解析与使用 reviver 解析的 JSPerf 比较:http: //jsperf.com/json-reviver。它表明,没有什么特别功能的自定义 reviver 速度要慢两倍,而具有昂贵功能的 reviver 则要慢得多。
但是,当将最后一种方法与使用原生 JSON 和“手动转换”的较弱方法进行比较时,差异似乎被忽略了。
注意:仅对单个值进行了基准测试。确保为您自己的(特定)案例创建自定义基准,因为不可能创建一个代表所有可能案例的基准。

我创建了一个JSPerf 测试用例来检查.toJSON. 为了隔离噪音,我创建了一个基于Date对象的测试用例。具有多个函数调用的自定义函数仅比原生函数慢两倍Date.prototype.toJSON

于 2012-06-18T15:40:44.690 回答
1

postMessage您可以使用特定的克隆方法,而不是使用。

我用这个:

function goclone(source) {
    if ($.isArray(source)) {
        var clone = [];
        for (var i=0; i<source.length; i++) {
            if (source[i]) clone[i] = goclone(source[i]);
        }
        return clone;
    } else if (typeof(source)=="object") {
        var clone = {};
        for (var prop in source) {
            if (source[prop]) {
                clone[prop] = goclone(source[prop]);
            }
        }
        return clone;
    } else {
        return source;
    }
}

它不会复制原型、函数等,并忽略null/NaN字段。

如果你不想使用 jquery,你可以自己编写一个isArray这样的函数

function isArray(obj) {
   return Object.prototype.toString.call(obj) === '[object Array]':
}
于 2012-06-18T15:34:26.063 回答
1

DOM 事件级别 2 可以被任何调用stopPropagation它正在处理的事件对象的方法的事件处理程序取消。如果您确保您的事件处理程序是页面上的第一个(主要是通过确保您的脚本标签是页面上的第一个),那么您可以调用stopPropagation以防止其他代码窃听您的消息。您也可以有选择地执行此操作,以确保仅过滤掉您的事件。

所以基本上你会这样做:

window.addEventListener("message", function (event) {
    var data = JSON.parse(event.data);

    if (data.secret === "my event and not anyone else's") {
        // do something
        event.stopPropagation();
    }
}, false);

但是请注意,人们仍然可以使用诸如greasemonkey 之类的工具来拦截您的事件。在网络上,您永远无法确定。JavaScript 是一种开源语言。希望这会有所帮助。

于 2012-06-18T15:40:06.063 回答