Отображение объектов JSON для объектов Javascript

При использовании AJAX я, как правило, передаю объекты с моего сервера на Javascript в виде объектов JSON (он же Javascript). Некоторые функции в моем 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-коде, и я полагаю, что я мог бы получить еще одно мнение или два о том, правильный способ сделать это, прежде чем я буду тратить час на час, фиксируя его в будущем.

EDIT: я решил принять решение jQuery, потому что я использовал jQuery в своем проекте. Однако есть несколько решений, которые также работали для меня, прежде чем я нашел параметр jQuery. Они просто были не такими чистыми и эффективными.

Ответы

Ответ 1

Следующее требует, чтобы у вас были одинаковые свойства в объекте и вашем объекте JSON.

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

Это создает новый объект PhoneNumber, а затем копирует на него все свойства вашего объекта JSON. Метод $.extend() относится к jQuery, но вы также можете использовать его в качестве аналогичного метода, например. Underscore.js или одна из других js-библиотек/фреймворков.

Ответ 2

В этом подобном вопросе есть много интересных ответов:

Разбирайте строку JSON в специальный прототип объекта в 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);

Ответ 3

AFAIK, во всем, что не является 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, сохраняя его DRY.

Ответ 4

Если поддержка старых браузеров не поддерживается, вы можете использовать Object.create, чтобы сделать сопоставление для вас. (отбрасывание прокладки - по крайней мере, прокладка на MDN-in будет не фиксировать старые браузеры, поскольку эта прокладка не принимает второй параметр.)

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 ...