Создание новой модели в backbone?

#javascript #object #backbone.js #new-operator

#javascript #объект #backbone.js #new-оператор

Вопрос:

Я хочу создать новую модель на основе некоторого параметра. Демонстрация JSBin

 var M1 = Backbone.Model.extend({
  defaults: { type: 'one', value: 1 }
});

var M2 = Backbone.Model.extend({
  defaults: { type: 'two', value: 2 }
});

var getModel = function(type) {
  var map = { 'one': M1, 'two': M2 };
  return map[type];
};

// Error in this line (Undefined is not a function)
var model = new getModel('two')();

console.log(model.get('value'));
  

Я попробовал несколько обозначений, но не смог точно указать причину.

1. Это работает нормально

 var mapModel = {
  'one': M1,
  'two': M2
};

new mapModel['two']();
  

2. Не работает

 var model = new (getModel('two')());
var model = (new getModel('two'))();
  

Я не понимаю, что такое undefiend и почему я вижу эту ошибку.

Комментарии:

1. ИМХО, я бы использовал следующее: нет необходимости в новой внешней функции getModel, я бы поместил ее внутрь (вернул новую карту [тип]). затем используйте getModel(‘two’), чтобы получить модель мгновенно.

2. @Evgeniy Я в порядке с использованием map, но я хочу понять причину ошибки?

3. @Evgeniy Спасибо за ваш ответ. Теперь я понимаю проблему и попытался объяснить ее в нескольких словах. Не стесняйтесь редактировать ответ, если считаете, что есть лучшее объяснение.

Ответ №1:

Я думаю, что в этом случае лучше обновить getModel функцию и делегировать ей создание экземпляров модели.Давайте создадим фабрику из getModel

 var getModel = function(type) {
    var map = { 'one': M1, 'two': M2 };
    return new map[type];
};
  

Затем вы можете использовать его для получения нового экземпляра модели надлежащего типа:

 var model = getModel('two');
  

Комментарии:

1. @Prinzhorn прав.. Вы также хотели создать фабрику моделей. Вы просто пропустили термин «фабрика», который имеет здесь большой вес 😉 Рад принять ваше решение 🙂

Ответ №2:

У меня есть причина, я столкнулся с проблемой. Давайте разберемся с ошибками одну за другой. Работающий JSBin

Нам нужно полностью понимать приоритет оператора new.

Пример # 1

 var model = new getModel('two')();
  

В этом случае new используется с методом getModel, и мы пытаемся снова вызвать то, что возвращается new getModel(‘два).

Пример #2, # 3

 var model = new (getModel('two')());
var model = (new getModel('two'))();
  

В этих случаях сначала вызывается все, что возвращается из getModel(‘two’), а затем создается экземпляр.

Решение

 var model = new (getModel('two'))();
  

Комментарии:

1. Может быть, переместить new внутрь getModel и назвать это фабрикой? Это избавит от всей путаницы (возможно, переименовать в createModel ).

2. @Prinzhorn Это действительно хорошее предложение. Почему я так не думал. С вами все в порядке.

3. @Prinzhorn Если вы добавите ответ, который вы говорите, я буду рад принять ваш 🙂

4. Я только что понял, что Евгений уже предлагал это в комментарии выше.

5. @Prinzhorn спасибо) если вы не возражаете, я опубликую эту идею в качестве альтернативного решения

Ответ №3:

Как насчет переноса new оператора в эту заводскую функцию?

 function createModel() {
  var object = new (arguments[0]);
  (arguments[0]).apply(object, [arguments[1]]);
  return object;
}

var model = createModel(getModel('two'));
var model2 = createModel(getModel('two'), { value: 4 });
console.log(model.get('value')); // 2
console.log(model2.get('value')); // 4
  

Редактировать
Вы также можете объединить фабричный метод с вашим текущим getModel

 var getModel = function() {
   var map = {
     'one': M1,
     'two': M2
   };
   var type = arguments[0];
   var M = map[type];
   var obj = new M;
   M.apply(obj, [arguments[1]]);
   return obj;
};
var model = getModel('two');
console.log(model.get('value')); // 2
var model2 = getModel('two', { value : 4});
console.log(model2.get('value')); // 4