我知道如何解析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月:这种“现代”方式是通过Object.assign
,但此功能在IE 11或更早的Android浏览器中不可用。
答案 0 :(得分:76)
当前答案包含大量手工或库代码。这不是必需的。
使用JSON.parse('{"a":1}')
创建普通对象。
使用其中一个标准化函数来设置原型:
Object.assign(new Foo, { a: 1 })
Object.setPrototypeOf({ a: 1 }, Foo.prototype)
答案 1 :(得分:68)
请参阅下面的示例(此示例使用本机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
答案 2 :(得分:37)
是否要添加JSON序列化/反序列化功能,对吧?然后看看这个:
你想实现这个目标:
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);
};
<强>用法强>:
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
注意:如果您需要,可以通过this.title
,this.author
等更改var title
,var author
等所有属性定义,并为其添加getter以完成UML定义。
答案 3 :(得分:18)
我觉得有用的博文: Understanding JavaScript Prototypes
你可以搞乱对象的__proto__属性。
var fooJSON = jQuery.parseJSON({"a":4, "b": 3});
fooJSON.__proto__ = Foo.prototype;
这允许fooJSON继承Foo原型。
我认为这不适用于IE,但至少从我读过的内容开始。
答案 4 :(得分:7)
我在问题中遗漏了什么,或者为什么自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
PS:你的问题很混乱:&gt;&gt; 这很棒,但是如何将JavaScript对象转换为特定的JavaScript对象(即使用某个原型)?
与标题相矛盾,您询问JSON解析,但引用的段落询问JS运行时对象原型替换。
答案 5 :(得分:2)
为了完整起见,这里有一个简单的单线程,我最终得到了(我不需要检查非Foo属性):
var Foo = function(){ this.bar = 1; };
// angular version
var foo = angular.extend(new Foo(), angular.fromJson('{ "bar" : 2 }'));
// jquery version
var foo = jQuery.extend(new Foo(), jQuery.parseJSON('{ "bar" : 3 }'));
答案 6 :(得分:2)
另一种方法可能是使用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);
答案 7 :(得分:2)
我创建了一个名为json-dry的包。它支持(循环)引用以及类实例。
你必须在你的类中定义2个新方法(原型toDry
和静态方法unDry
),注册类(Dry.registerClass
),然后离开。
答案 8 :(得分:1)
我喜欢在构造函数中添加一个可选参数并调用Object.assign(this, obj)
,然后处理对象或对象数组本身的任何属性:
constructor(obj) {
if (obj != null) {
Object.assign(this, obj);
if (this.ingredients != null) {
this.ingredients = this.ingredients.map(x => new Ingredient(x));
}
}
}
答案 9 :(得分:0)
虽然这在技术上并不是你想要的,但如果你事先知道你想要处理的对象类型,你可以使用已知对象原型的call / apply方法。
你可以改变这个
alert(fooJSON.test() ); //Prints 12
到这个
alert(Foo.prototype.test.call(fooJSON); //Prints 12
答案 10 :(得分:0)
我将我能够找到的解决方案组合成一个通用的解决方案,它可以自动解析自定义对象及其所有字段,因此您可以在反序列化后使用原型方法。
一个假设是你定义了一个特殊字段,表明它是你要自动应用它的每个对象的类型(在示例中为this.__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);
}
答案 11 :(得分:0)
当前接受的答案不适用于我。您需要正确使用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
答案 12 :(得分:-2)
Olivers的答案非常明确,但是如果你正在寻找角度js的解决方案,我已经写了一个很好的模块,名为Angular-jsClass,这样做很容易,当你的目标是使用litaral符号定义的对象总是很糟糕一个大项目,但说开发人员面临BMiner所说的问题,如何将json序列化为原型或构造函数符号对象
var jone = new Student();
jone.populate(jsonString); // populate Student class with Json string
console.log(jone.getName()); // Student Object is ready to use