2012-01-09 28 views
16

Cuando uso AJAX, tiendo a pasar objetos de mi servidor a Javascript en forma de objetos JSON (también conocido como Javascript). Ciertas funciones dentro de mi Javascript dependen del tipo específico de objeto que estoy usando. Por ejemplo, usemos un número de teléfono, por ejemplo. Tengo un constructor:Asignación de objetos JSON a objetos 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; 
} 

Que uso al crear un objeto de número de teléfono en mi Javascript. En algunas situaciones, no creo el objeto en JS, obtengo el objeto del servidor, por lo que viene en forma de un objeto genérico con exactamente los mismos campos. Así que cuando mi código se basa en el tipo específico mediante el uso de algo como esto:

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]); 
} 

En esta situación, puedo comprobar el nombre del constructor de objetos y establecer ciertas variables sobre la base de ese nombre. Si el objeto que verifico el nombre es un JSON del servidor, simplemente me da una respuesta genérica de "Objeto" y, por lo tanto, el código no funciona. Me evitar esto mediante el uso de una función de mapeo para cada objeto, tales como:

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; 
} 

Esto funciona muy bien, pero me parece un poco redundante. ¿Es esta la mejor manera de resolver el problema del objeto JSON, o hay una mejor solución? Entiendo que esto es más un tipo de pregunta "¿Lo estoy haciendo de la mejor manera posible?", Pero repito este tipo de lógica CONSTANTEMENTE en mi código Javascript y me parece que podría obtener otra opinión o no sobre si es o no la forma correcta de hacer esto antes de tener que pasar hora tras hora arreglándolo en el futuro.

EDIT: Terminé aceptando una solución jQuery porque uso jQuery en mi proyecto. Sin embargo, hay varias soluciones que también me funcionaron antes de encontrar la opción jQuery. Simplemente no eran tan limpios y eficientes.

+4

* "objetos JSON (JavaScript) también conocido como" * JSON no es conocido como JavaScript. Tiene su propio nombre porque tiene su propia sintaxis y especificación. –

Respuesta

25

Lo siguiente requiere que tenga las mismas propiedades en su objeto y su objeto JSON.

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

Esto básicamente crea un nuevo objeto PhoneNumber y luego copia todas las propiedades de su objeto JSON en él. El método $.extend() es de jQuery, pero también puede usar un método similar de, por ejemplo, Underscore.js o uno de los otros js libraries/frameworks.

+0

Uso jQuery, así que esto puede ser una una solución aún más fácil para mí. – ryandlf

+3

Si usa angular, puede hacer 'var phoneNumber = angular.copy (suJSONObject, new PhoneNumber())'. Puede que no tenga esa sintaxis correcta, pero puedes hacerlo, ¡y esa es la función que deseas! – Chris

+1

Para angular puede usar angular.copy(), angular.extend() o angular.merge(). Copiar elimina las propiedades de su nuevo objeto y luego clona las propiedades del objeto de origen. Extender y fusionar trae las propiedades del objeto fuente al nuevo objeto (a través de una copia superficial y profunda, respectivamente), manteniendo las propiedades existentes del nuevo objeto. http://davidcai.github.io/blog/posts/copy-vs-extend-vs-merge/ – Nhan

1

Si no es compatible con navegadores antiguos, puede usar Object.create para realizar la asignación para usted. (Dejando caer la cuña, por lo menos la cuña en el MDN-in no fijar los navegadores más antiguos, ya que la cuña no acepta el segundo parámetro.)

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

yo sepa, en todo lo que es no IE, usted puede hacer esto:

// 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(); 

Por desgracia, IE no admite el descriptor de acceso __proto__, así que lo que tendría que hacer primero es crear una instancia vacía de su objeto, a continuación, sólo poli Y todo a través de:

// 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(); 

Ambos enfoques son un poco más genérico que sus funciones mapWhatever, lo mantiene seco.

+0

Parece una solución limpiadora. Esto es lo que estaba buscando, gracias. Suponiendo que mi prueba funciona, parece una respuesta aceptada. – ryandlf

+1

Downvoted dos años después de que Amadan publicara su respuesta. Nunca se debe acceder al prototipo con __proto__ ya que está obsoleto: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto –

3

Esta pregunta similar tiene muchas respuestas interesantes:

Parse JSON String into a Particular Object Prototype in JavaScript

Basado de la respuesta del propio cartel, creo que esto sería una solución eficaz para usted:

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; 
} 

Se hará necesita agregar objectType a los objetos JSON que está recibiendo para definir la clase javascript que quiere crear una instancia. Luego, cuando llame a esta función, lanzará el objeto a ese tipo y copiará los datos (incluida la variable 'objectType').

Usando su ejemplo el número de teléfono, el código se vería así:

// 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); 
Cuestiones relacionadas