2012-01-09 474 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);