如何将继承的对象字符串化为JSON?

wtj*_*nes 31 javascript json

使用JSON.stringify()时,json2.js似乎忽略了父对象的成员.例:

require('./json2.js');

function WorldObject(type) {    
    this.position = 4;
}

function Actor(val) {
    this.someVal = 50;
}

Actor.prototype = new WorldObject();

var a = new Actor(2);

console.log(a.position);
console.log(JSON.stringify(a));
Run Code Online (Sandbox Code Playgroud)

输出是:

4
{"someVal":50}
Run Code Online (Sandbox Code Playgroud)

我希望这个输出:

4
{"position":0, "someVal":50}
Run Code Online (Sandbox Code Playgroud)

Tom*_*ana 34

那就是它的方式,JSON.stringify不保留对象的任何非拥有属性.您可以在这里查看有关其他缺点和可能的解决方法的有趣讨论.

另请注意,作者不仅记录了问题,还编写了一个名为HydrateJS的库,可能对您有所帮助.

这个问题比第一眼看上去要深一点.即使它a真的会字符串化{"position":0, "someVal":50},然后解析它会创建一个具有所需属性的对象,但既不是Actor的实例,也不是它与WorldObject的原型链接(毕竟,解析方法没有这个信息,所以它不可能那样恢复).

为了保护原型链,需要巧妙的技巧(如HydrateJS中使用的那些).如果这不是您的目标,也许您只需要在对其进行字符串化之前"展平"该对象.要做到这一点,您可以例如迭代对象的所有属性,无论它们是否属于它们并重新分配它们(这将确保它们在对象本身上定义而不是仅从原型继承).

function flatten(obj) {
    var result = Object.create(obj);
    for(var key in result) {
        result[key] = result[key];
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

写入函数的方式不会改变原始对象.所以使用

console.log(JSON.stringify(flatten(a)));
Run Code Online (Sandbox Code Playgroud)

你会得到你想要的输出,并a保持不变.


Ces*_*ela 21

另一种选择是toJSON在要序列化的对象原型中定义一个方法:

function Test(){}

Test.prototype = {

    someProperty: "some value", 

    toJSON: function() {
        var tmp = {};

        for(var key in this) {
            if(typeof this[key] !== 'function')
                tmp[key] = this[key];
        }

        return tmp;
    }
};

var t = new Test;

JSON.stringify(t); // returns "{"someProperty" : "some value"}"
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为JSON.stringify toJSON在尝试本机序列化之前在其接收的对象中搜索方法.


tec*_*bar 9

检查这个小提琴:http://jsfiddle.net/AEGYG/

您可以使用此函数对对象进行扁平化:

function flatStringify(x) {
    for(var i in x) {
        if(!x.hasOwnProperty(i)) {
            // weird as it might seem, this actually does the trick! - adds parent property to self
            x[i] = x[i];
        }
    }
    return JSON.stringify(x);
}
Run Code Online (Sandbox Code Playgroud)

  • 这会改变原始对象,这对于通用答案来说真的很糟糕。 (2认同)

kie*_*wic 5

这是他的答案中包含的代码段@TomasVana 的递归版本,以防在对象树的多个级别存在继承:

var flatten = function(obj) {
    if (obj === null) {
        return null;
    }

    if (Array.isArray(obj)) {
        var newObj = [];
        for (var i = 0; i < obj.length; i++) {
            if (typeof obj[i] === 'object') {
                newObj.push(flatten(obj[i]));
            }
            else {
                newObj.push(obj[i]);
            }
        }
        return newObj;
    }

    var result = Object.create(obj);
    for(var key in result) {
        if (typeof result[key] === 'object') {
            result[key] = flatten(result[key]);
        }
        else {
            result[key] = result[key];
        }
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

并将数组保留为数组。以同样的方式调用它:

console.log(JSON.stringify(flatten(visualDataViews)));
Run Code Online (Sandbox Code Playgroud)