我知道如何解析JSON字符串并将其转换为JavaScript对象。 您可以在现代浏览器(和IE9+)中使用JSON.parse()。

这很好,但我怎么能把这个JavaScript对象,并把它变成一个特定的JavaScript对象(即与特定的原型)?

例如,假设你有:

function Foo()
{
   this.a = 3;
   this.b = 2;
   this.test = function() {return this.a*this.b;};
}
var fooObj = new Foo();
alert(fooObj.test() ); //Prints 6
var fooJSON = JSON.parse({"a":4, "b": 3});
//Something to convert fooJSON into a Foo Object
//....... (this is what I am missing)
alert(fooJSON.test() ); //Prints 12

同样,我不知道如何将JSON字符串转换为通用的JavaScript对象。我想知道如何将JSON字符串转换为“Foo”对象。也就是说,我的对象现在应该有一个函数'test'和属性'a'和'b'。

更新 在做了一些研究之后,我想到了这个……

Object.cast = function cast(rawObj, constructor)
{
    var obj = new constructor();
    for(var i in rawObj)
        obj[i] = rawObj[i];
    return obj;
}
var fooJSON = Object.cast({"a":4, "b": 3}, Foo);

这样能行吗?

2017年5月更新:“现代”的方式是通过对象。但该功能在ie11或更老的Android浏览器中不可用。


当前回答

我已经结合了我能够找到的解决方案,并将其编译成一个通用的解决方案,可以自动递归地解析自定义对象及其所有字段,以便在反序列化后使用原型方法。

一个假设是,您定义了一个特殊的字段,该字段在您想要自动应用它的类型的每个对象中指示它的类型。__type在例子中)。

function Msg(data) {
    //... your init code
    this.data = data //can be another object or an array of objects of custom types. 
                     //If those objects defines `this.__type', their types will be assigned automatically as well
    this.__type = "Msg"; // <- store the object's type to assign it automatically
}

Msg.prototype = {
    createErrorMsg: function(errorMsg){
        return new Msg(0, null, errorMsg)
    },
    isSuccess: function(){
        return this.errorMsg == null;
    }
}

用法:

var responseMsg = //json string of Msg object received;
responseMsg = assignType(responseMsg);

if(responseMsg.isSuccess()){ // isSuccess() is now available
      //furhter logic
      //...
}

类型赋值函数(它递归地将类型赋给任何嵌套对象;它还遍历数组以找到任何合适的对象):

function assignType(object){
    if(object && typeof(object) === 'object' && window[object.__type]) {
        object = assignTypeRecursion(object.__type, object);
    }
    return object;
}

function assignTypeRecursion(type, object){
    for (var key in object) {
        if (object.hasOwnProperty(key)) {
            var obj = object[key];
            if(Array.isArray(obj)){
                 for(var i = 0; i < obj.length; ++i){
                     var arrItem = obj[i];
                     if(arrItem && typeof(arrItem) === 'object' && window[arrItem.__type]) {
                         obj[i] = assignTypeRecursion(arrItem.__type, arrItem);
                     }
                 }
            } else  if(obj && typeof(obj) === 'object' && window[obj.__type]) {
                object[key] = assignTypeRecursion(obj.__type, obj);
            }
        }
    }
    return Object.assign(new window[type](), object);
}

其他回答

我是否在问题中遗漏了一些东西,或者为什么没有人提到JSON的恢复参数。从2011年开始解析?

下面是简单的解决方案代码: https://jsfiddle.net/Ldr2utrr/

function Foo()
{
   this.a = 3;
   this.b = 2;
   this.test = function() {return this.a*this.b;};
}


var fooObj = new Foo();
alert(fooObj.test() ); //Prints 6
var fooJSON = JSON.parse(`{"a":4, "b": 3}`, function(key,value){
if(key!=="") return value; //logic of course should be more complex for handling nested objects etc.
  let res = new Foo();
  res.a = value.a;
  res.b = value.b;
  return res;
});
// Here you already get Foo object back
alert(fooJSON.test() ); //Prints 12

PS:你的问题令人困惑:>>这很好,但我如何将JavaScript对象转化为特定的JavaScript对象(即具有特定的原型)? 与标题相矛盾的是,你问的是JSON解析,但引用的段落问的是JS运行时对象原型替换。

另一种方法可以使用Object.create。第一个参数传递原型,第二个参数传递属性名映射到描述符:

function SomeConstructor() { }; SomeConstructor.prototype = { doStuff: function() { console.log("Some stuff"); } }; var jsonText = '{ "text": "hello wrold" }'; var deserialized = JSON.parse(jsonText); // This will build a property to descriptor map // required for #2 argument of Object.create var descriptors = Object.keys(deserialized) .reduce(function(result, property) { result[property] = Object.getOwnPropertyDescriptor(deserialized, property); }, {}); var obj = Object.create(SomeConstructor.prototype, descriptors);

我创建了一个名为json-dry的包。它支持(循环)引用和类实例。

你必须在你的类中定义2个新方法(原型上的toDry和静态方法unDry),注册类(Dry.registerClass),然后就可以开始了。

请参见下面的示例(此示例使用本机JSON对象)。我的改动用大写字母注释:

function Foo(obj) // CONSTRUCTOR CAN BE OVERLOADED WITH AN OBJECT
{
    this.a = 3;
    this.b = 2;
    this.test = function() {return this.a*this.b;};

    // IF AN OBJECT WAS PASSED THEN INITIALISE PROPERTIES FROM THAT OBJECT
    for (var prop in obj) this[prop] = obj[prop];
}

var fooObj = new Foo();
alert(fooObj.test() ); //Prints 6

// INITIALISE A NEW FOO AND PASS THE PARSED JSON OBJECT TO IT
var fooJSON = new Foo(JSON.parse('{"a":4,"b":3}'));

alert(fooJSON.test() ); //Prints 12

目前公认的答案对我不起作用。你需要正确使用Object.assign():

class Person {
    constructor(name, age){
        this.name = name;
        this.age = age;
    }

    greet(){
        return `hello my name is ${ this.name } and i am ${ this.age } years old`;
    }
}

你通常创建这个类的对象:

let matt = new Person('matt', 12);
console.log(matt.greet()); // prints "hello my name is matt and i am 12 years old"

如果你有一个json字符串,你需要解析到Person类,这样做:

let str = '{"name": "john", "age": 15}';
let john = JSON.parse(str); // parses string into normal Object type

console.log(john.greet()); // error!!

john = Object.assign(Person.prototype, john); // now john is a Person type
console.log(john.greet()); // now this works