在JavaScript中将JSON字符串解析为特定对象原型

BMi*_*ner 163 javascript parsing json prototype object

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

这很好,但是如何将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
Run Code Online (Sandbox Code Playgroud)

同样,我不知道如何将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);
Run Code Online (Sandbox Code Playgroud)

那会有用吗?

更新2017年5月:执行此操作的"现代"方式是通过Object.assign,但此功能在IE 11或更早版本的Android浏览器中不可用.

Eri*_*zen 101

当前答案包含大量手工或库代码.这不是必需的.

  1. 使用JSON.parse('{"a":1}')创建一个普通的对象.

  2. 使用其中一个标准化函数来设置原型:

    • Object.assign(new Foo, { a: 1 })
    • Object.setPrototypeOf({ a: 1 }, Foo.prototype)

  • 如果存在一些也需要原型的属性,则设置原型的解决方案不起作用.换句话说:它只解决第一级数据层次结构. (6认同)
  • 对使用`Object.setPrototypeOf(...)`也有一个很大的警告.https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf (4认同)
  • Object.assign在旧版浏览器中不可用,包括IE和较旧的Android浏览器.http://kangax.github.io/compat-table/es6/#test-Object_static_methods_Object.assign (2认同)
  • 在下面查看我的解决方案,该解决方案递归地应用Object.assign(..),它可以自动解析属性(预先提供了一些信息) (2认同)

Oli*_*ran 70

请参阅下面的示例(此示例使用本机JSON对象).我的更改在CAPITALS评论:

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
Run Code Online (Sandbox Code Playgroud)

  • 您可能希望保护自己免受原型属性的影响.`for(var ob in obj){if(obj.hasOwnProperty(prop)){this [prop] = obj [prop];}}` (11认同)
  • 这非常危险.如果obj有一个不在Foo定义中的属性,你将创建一个具有额外隐藏属性的Foo对象,你不知道它的名字......而不是一个循环,我只会这样做:this.a = obj. a和this.b = obj.b. 或直接我会传递"a"和"b"作为参数:new Foo(obj.a,obj.b) (7认同)
  • @RomainVergnory对于更安全,我只初始化在构造函数创建的属性,这代替OBJ:`用于(在OBJ VAR丙){如果(this.hasOwnProperty(丙)){这里[丙] = OBJ [丙]; }}`.这假设您希望服务器填充所有属性,如果obj.hasOwnProperty()失败,IMO也应该抛出... (3认同)
  • GagleKas的建议值得一听。(尽管“非常危险”有点OTT。)上面的示例只是为了给您一个想法。正确的实现将取决于您的应用程序。 (2认同)

Gab*_*mas 40

是否要添加JSON序列化/反序列化功能,对吧?然后看看这个:

你想实现这个目标:

UML

toJson()是一种常规方法.
fromJson()是一个静态方法.

实施:

var Book = function (title, author, isbn, price, stock){
    this.title = title;
    this.author = author;
    this.isbn = isbn;
    this.price = price;
    this.stock = stock;

    this.toJson = function (){
        return ("{" +
            "\"title\":\"" + this.title + "\"," +
            "\"author\":\"" + this.author + "\"," +
            "\"isbn\":\"" + this.isbn + "\"," +
            "\"price\":" + this.price + "," +
            "\"stock\":" + this.stock +
        "}");
    };
};

Book.fromJson = function (json){
    var obj = JSON.parse (json);
    return new Book (obj.title, obj.author, obj.isbn, obj.price, obj.stock);
};
Run Code Online (Sandbox Code Playgroud)

用法:

var book = new Book ("t", "a", "i", 10, 10);
var json = book.toJson ();
alert (json); //prints: {"title":"t","author":"a","isbn":"i","price":10,"stock":10}

var book = Book.fromJson (json);
alert (book.title); //prints: t
Run Code Online (Sandbox Code Playgroud)

注意:如果你愿意,你可以改变像所有的属性定义this.title,this.author等的var title,var author等等,并添加干将给他们完成UML定义.

  • 这些天我会使用`JSON.stringify()`而不是自己编写toJSon().现在所有现代浏览器都支持它,无需重新发明轮子. (5认同)
  • 我同意.这个实现肯定会起作用,而且它很棒......只是有点罗嗦而且特定于Book对象.恕我直言,JS的力量来自原型,并且如果你愿意,还可以拥有一些额外的属性.这就是我所说的全部.我真的在寻找单行:x .__ proto__ = X.prototype; (虽然目前不兼容IE浏览器) (4认同)
  • 不要忘记你的`toJson()`方法 - 无论它是否具有硬编码的单独属性或者为每个属性使用 - 都需要为每个字符串属性中的某些字符添加反斜杠转义码.(例如,书名可能带有引号.) (3认同)
  • 同意@skypecakes.如果只想序列化属性的子集,请创建可序列化属性的常量.`serializable = ['title','author',...]`.`JSON.stringify(serializable.reduce((obj,prop)=> {... obj,[prop]:this [prop]},{}))` (2认同)

BMi*_*ner 18

我发现有用的博客文章: 了解JavaScript原型

你可以搞乱Object的__proto__属性.

var fooJSON = jQuery.parseJSON({"a":4, "b": 3});
fooJSON.__proto__ = Foo.prototype;
Run Code Online (Sandbox Code Playgroud)

这允许fooJSON继承Foo原型.

我认为这不适用于IE,但至少从我读过的内容开始.

  • 请注意,`__ proto__`早已[已弃用](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto).此外,出于性能原因,不建议修改已创建对象的[[Prototype]]内部属性(通过设置`__proto__`或通过任何其他方式). (13认同)
  • 我想这些天,人们会调用`Object.setPrototypeOf(fooJSON,Foo.prototype)`而不是设置`fooJSON .__ proto__` ...对吗? (3认同)
  • 实际上,这样的事情是我的第一直觉. (2认同)

Luk*_*one 15

目前接受的答案对我不起作用。您需要正确使用 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`;
    }
}
Run Code Online (Sandbox Code Playgroud)

您通常创建此类的对象:

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

如果您有一个 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

Run Code Online (Sandbox Code Playgroud)


Phi*_*nin 9

我在问题中遗漏了什么,或者为什么没有人提到自2011年以来的reviver参数JSON.parse

以下是解决方案的简单代码: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
Run Code Online (Sandbox Code Playgroud)

PS:你的问题很混乱:>> 那很好,但是如何将JavaScript对象转换为特定的JavaScript对象(即使用某个原型)? 与标题相矛盾,您询问JSON解析,但引用的段落询问JS运行时对象原型替换.