2016-01-11 3 views
0

Допустим, у меня есть этот объект:Создание прототипов для подобъектов, JavaScript

var order = { 
    customer: 'Joe', 
    items: [ 
    { 
     id: 123, 
     title: 'VCR', 
    } 
    ] 
}; 

Я хочу создать логику и порядок и элементы объекта. Поэтому мне нужно написать класс, который создает экземпляр другого класса.

Класс заказа:

function Order(customer, items){ 
    this.customer = customer; 
    this.items = items; 
} 

Order.prototype = { 
    getCustomer: function(){ 
    console.log(this.customer); 
    } 
}; 

Деталь Класс:

Экземпляр:

var myOrder = new Order(order.customer, order.items); 

Теперь это то, что я хочу сделать:

myOrder.items[0].getItemId() //123 
myOrder.items[0].getCustomer() //Joe 

Как это сделать? Мне нужно как-то связать классы и добавить прототип к объектам объекта.

Jsbin: https://jsbin.com/nofofifuka/edit?html,js,console

+0

Добавить свойство «заказать» к элементу и передать объект заказа при его создании. – Pointy

+3

Есть ли причина, почему у вас есть класс 'Order' с одним элементом, который является объектом' order'? Почему бы не сделать ваши объекты 'Order' вместо полей' customer' и 'items'? То есть, сделайте 'Order' модель, которая представляет те же данные, что и ваш объект, вместо оболочки. – apsillers

+0

@ capsillers Да, вы правы. Починил это. – Per

ответ

0

Вы можете использовать Array.prototype.map вызвать Item конструктор по элементам в items.

function Order(order){ 
    this.customer = customer; 
    this.items = order.items.map(function (item) { 
     return new Item(item); 
    }); 
} 

Array.prototype.map вызывает данную функцию один раз для каждого элемента в исходном массиве и возвращает новый массив той же длины, содержащий результаты вызывающей функции.

В качестве альтернативы вы можете сделать ваш Item конструктор имеет несколько дополнительных СМАРТС, поэтому он может создать экземпляр себя, если вызывается без new:

function Item(item){ 
    if (! (this instanceof Item)) { return new Item(item); } 
    this.id = id; 
    this.title = title; 
} 

Затем вы можете использовать его непосредственно в map:

function Order(order){ 
    this.order = order; 
    order.items = order.items.map(Item); 
} 
+0

Обратите внимание, что это будет мутировать объект, пройденный, если OP заботится об этом. (Фактически, ОП только изменил структуру кода, которая позволяет избежать этой проблемы, но также делает текущую формулировку кода вашего ответа отличной от вопроса.) – apsillers

+0

С помощью этого решения вы получаете идентичный прототип для каждого элемента. Это занимает ненужную память. У вас есть способ, если вы можете поставить один прототип «один уровень вверх», который обрабатывает логику элементов? – Per

+0

На самом деле, как прототипы работают уже :) Вещи в прототипе не копируются при создании экземпляра класса. Таким образом, в памяти будет только один «getItemId». См. Https://github.com/getify/You-Dont-Know-JS/blob/master/this%20&%20object%20prototypes/ch5.md – N3dst4

0

Я думаю, что вы хотите достичь, не имеет ничего общего с наследованием. Можете ли вы проверить, удовлетворяет ли код ниже того, чего вы хотите достичь?

function Order(id){ 
    this.id = id; 
    this.items = []; 
} 

Order.prototype.addItem = function(item) { 
    this.items.push(item); 
}; 

Order.prototype.getItems = function() { 
    return this.items; 
}; 

Order.prototype.getItem = function(id) { 
    for (var i = 0, l = this.items.length; i<l; i++) { 
    if (this.items[i].id === id) return this.items[i]; 
    } 

    return; 
}; 

function Item(id, customer) { 
    this.id = id; 
    this.customer = customer; 
} 

var order1 = new Order(1); 
order1.addItem(new Item(123, 'customer1')); 
order1.addItem(new Item(345, 'customer2')); 
order1.addItem(new Item(456, 'customer3')); 

console.log(order1.getItems()); 
console.log(order1.getItem(345)); 
+0

Я считаю, что информация о клиенте должна принадлежать классу заказа, но зависит от проекта конечно. –

0

На мой взгляд, такой случай должен отражать следующую ситуацию в реальной жизни:
Некоторые покупатель (customer) делает order, который может содержит много позиций продукта (items).
Эти предметы имеют свои уникальные характеристики и должны добавляться отдельно в заказ. Класс заказа:

function Order(customer){ 
     this.customer = customer; 
     this.items = []; 
    } 

    Order.prototype = { 
     constructor: Order, 
     addItem: function(id, title){ 
     this.items.push(new Item(id, title)); 
     }, 
     getCustomer: function(){ 
     console.log(this.customer); 
     } 
    }; 

Деталь Класс:

function Item(id, title){ 
    this.id = id; 
    this.title = title; 
} 

Item.prototype = { 
    constructor: Item, 
    getItemId: function(){ 
    console.log(this.id); 
    } 
}; 

Экземпляр:

var myOrder = new Order(order.customer); 
order.items.map(function (item) { 
    myOrder.addItem(item.id, ite.title); 
}); 

myOrder.items[0].getItemId() //123 
0

Array.prototype.map является правильным инструментом, но для того, чтобы поставить логику вы просите, Я думаю, что его следует использовать больше:

function Order(o){ 
    this.items = o.items.map(function(obj){ 
     obj.customer = o.customer; 
     var r = obj; 
     r.getItemId = function(){ console.log(obj.id); }; 
     r.getItemTitle = function(){ console.log(obj.title); }; 
     r.getCustomer = function(){ console.log(obj.customer); }; 
     return r; 
    }); 
} 

var myOrder = new Order(order); 

myOrder.items[0].getCustomer(); 
myOrder.items[0].getItemId(); 
myOrder.items[0].getItemTitle(); 

Учитывая код, я не добавил выше, но благодаря строке 4 (var r = obj;) вы можете использовать свойства клиента, id и title myOrder.items[n], а также все геттеры.

Смежные вопросы