2012-01-09 407 views
16

当使用AJAX时,我倾向于将对象从我的服务器以JSON对象(又名Javascript)的形式传递给Javascript。我的Javascript中的某些函数依赖于我正在使用的特定类型的对象。例如,让我们用一个电话号码为例。我有一个构造函数:将JSON对象映射到Javascript对象

function PhoneNumber(number, type, isPrimary, contactId, id, className) { 
    this.number = number; 
    this.type = type; 
    this.isPrimary = isPrimary; 
    this.contactId = contactId; 
    this.id = id; 
    this.className = className; 
} 

我在Javascript中创建电话号码对象时使用了哪一个。在某些情况下,我不会在JS中创建对象,我从服务器获取对象,因此它以具有完全相同字段的通用对象的形式出现。所以,当我的代码使用一些诸如这依赖于特定类型:

var objType = objArray[i].constructor.name; 
var mappedObj; 

switch(objType) { 
    case 'PhoneNumber': 
     currentArray = currentArray.phone; 
     //Convert response to javascript object. 
     mappedObj = mapPhone(jsonResponse[i]); 
     break; 
    case 'Email': 
     currentArray = currentArray.email; 
     mappedObj = mapEmail(jsonResponse[i]); 
     break; 
    case 'Address': 
     currentArray = currentArray.address; 
     mappedObj = mapAddress(jsonResponse[i]); 
     break; 
    case 'Website': 
     currentArray = currentArray.website; 
     mappedObj = mapWebsite(jsonResponse[i]); 
} 

在这种情况下,我检查对象的构造函数的名称,并基于该名称设置某些变量。如果我检查名称的对象是来自服务器的JSON,它只是给我一个通用的“对象”响应,因此代码不起作用。我通过使用映射函数为每个对象解决这个问题,例如:

function mapPhone(phoneObj) { 
    var id = phoneObj.id; 
    var contactId = phoneObj.contactId; 
    var number = phoneObj.number; 
    var type = phoneObj.type; 
    var primary = phoneObj.isPrimary; 
    var className = phoneObj.className; 
    var phoneNumber = new PhoneNumber(number, type, primary, contactId, id, className); 
    return phoneNumber; 
} 

这工作得很好,但对我来说似乎有点多余。这是解决JSON对象问题的最佳方法,还是有更好的解决方案?我知道这更像是一个“我是否尽可能做到最好的方式”类型的问题,但我常常在我的Javascript代码中重复这种类型的逻辑,并且我想我可能会就另一个或两个问题得到另一个意见在我必须花费一小时一小时修复它之前做到这一点的正确方法。

编辑:我结束了接受jQuery解决方案,因为我碰巧在我的项目中使用jQuery。然而,在我找到jQuery选项之前,有多种解决方案也适用于我。他们只是没有那么干净和高效。

+4

* “JSON对象(又称JavaScript)” * JSON是不是又名的JavaScript。它有自己的名字,因为它有自己的语法和规范。 – 2012-01-09 02:37:36

回答

25

以下要求您在对象和JSON对象中具有相同的属性。

var phoneNumber = $.extend(new PhoneNumber(), yourJSONObject); 

这基本上创建一个新的PhoneNumber对象,然后将所有属性从您的JSON对象复制到它。 $.extend()方法来自jQuery,但您也可以使用来自例如类似的方法。 Underscore.js或其他js库/框架之一。

+0

我确实使用jQuery,所以这可能是一个更容易解决我的问题。 – ryandlf 2012-01-09 03:33:22

+3

如果你使用angular,你可以做'var phoneNumber = angular.copy(yourJSONObject,new PhoneNumber())'。我可能没有这种语法,但你可以做到,那就是你想要的功能! – Chris 2015-11-07 17:05:43

+1

对于角度,您可以使用angular.copy(),angular.extend()或angular.merge()。复制剥离新对象的属性,然后克隆源对象的属性。扩展和合并将源对象的属性引入新对象(分别通过浅层和深层复制),同时仍保留新对象的现有属性。 http://davidcai.github.io/blog/posts/copy-vs-extend-vs-merge/ – Nhan 2016-11-18 07:42:24

1

如果不支持以前的浏览器是好的,您可以使用Object.create为您做的映射

DEMO

function makeThisExtend(obj, CtorFunc) { 
    for (var k in obj) 
     if ({}.hasOwnProperty.call(obj, k)) 
      obj[k] = { value: obj[k] }; 

    return Object.create(CtorFunc.prototype, obj); 
} 

var objFromServer = { Number: "123", id: 5 }; 
objFromServer = makeThisExtend(objFromServer, PhoneNumber); 


alert(objFromServer.Number + " " + objFromServer.id); //123 5 
alert(objFromServer.constructor); //function PhoneNumber ... 
2

据我所知,在一切,这是(在MDN-将修复旧的浏览器,因为该垫片不接受第二个参数。下降匀场至少垫片)不是IE,你可以这样做:

// define a class 
var Foo = function(name) { 
    this.name = name; 
} 
// make a method 
Foo.prototype.shout = function() { 
    return "I am " + this.name; 
} 
// make a simple object from JSON: 
var x = JSON.parse('{ "name": "Jason" }'); 
// force its class to be Foo 
x.__proto__ = Foo.prototype; 
// the method works 
x.shout(); 

不幸的是,IE不支持__proto__访问,所以你需要做的是先创建对象的空实例什么,然后就警察Ÿ所做的一切:

// make a simple object from JSON: 
var x = JSON.parse('{ "name": "Jason" }'); 
// make an empty Foo 
var y = Object.create(Foo.prototype); 
// copy stuff over 
for (a in x) { 
    y[a] = x[a]; 
} 
y.shout(); 

这两种方法比你mapWhatever功能更通用的相当多,保持其干燥。

+0

看起来更清洁的解决方案。这是我正在寻找的,谢谢。假设我的测试工作,这看起来像一个被接受的答案。 – ryandlf 2012-01-09 03:03:21

+1

在Amadan发布他的答案后两年下来。一个人不应该使用__proto__访问原型,因为这已被弃用:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto – 2014-12-01 13:44:51

3

这类似的问题,有很多有趣的答案:

Parse JSON String into a Particular Object Prototype in JavaScript

基于关闭海报自己的答案,我认为这将是你的一个有效的解决方案:

function recastJSON(jsonObject) { 
    // return generic object if objectType is not specified 
    if (!jsonObject.objectType) 
     return jsonObject; 

    // otherwise create a new object of type specified 
    var obj = eval('new '+jsonObject.objectType+'()'); 
    for(var i in jsonObject) 
     obj[i] = jsonObject[i]; 
    return obj; 
} 

你会需要将objectType添加到您接收的JSON对象中,以定义要实例化的JavaScript类。然后当你调用这个函数时,它会将该对象转换为该类型并复制数据(包括变量'objectType')。

使用您的手机号码,例如,你的代码应该是这样的:

// generic object from JSON 
var genericObject = {objectType:'PhoneNumber', number:'555-555-5555', type:'home', primary:true, contactId:123, id:1234, className:'stdPhone'}; 
var phoneObject = recastJSON(genericObject);