#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