Массивы в модели Backbone.js по существу статичны? - PullRequest
4 голосов
/ 02 апреля 2012

Почему массивы в модели Backbone.js по сути являются статическими переменными?

class exports.Content extends Backbone.Model
    tags: []

, тогда, если я сделаю несколько моделей:

contentA = new Content()
contentB = new Content()

и добавлю одну строку к каждой модели 'массив:

contentA.tags.push('hello')
contentB.tags.push('world')

они оба заканчиваются одним и тем же массивом:

contentB.tags // ['hello','world']

, но если это строка, то проблем нет:

contentA.name = "c1"
contentB.name = "c2"

contentA.name // "c1"

Ответы [ 4 ]

15 голосов
/ 02 апреля 2012

Краткий ответ

Когда вы вызываете extends, чтобы определить свой объект, вы передаете конфигурацию нового объекта как литерал объекта.Объекты передаются по ссылке, а функция extends передает только ссылку на массив тегов в определение нового типа.

Как отмечали другие, вы можете исправить это, назначив tags функции,Это работает, потому что функция задерживает оценку tags, пока объект не будет создан.Нет ничего нативного в JavaScript, который делает это, но сам Backbone распознает tags как функцию или значение.

Длинный ответ

Несмотря на то, что ваш код в CoffeeScript, этотсводится к комбинации нескольких вещей в JavaScript:

  • В JavaScript нет классов
  • Литералы объекта вычисляются немедленно
  • Объекты JavaScript передаютсяссылка

В JavaScript нет классов.Период.CoffeeScript дает вам представление о классе, но в действительности он компилируется в JavaScript, который не имеет классов.

Вы можете иметь типы и определения типов (функции конструктора), но не классы.Backbone предоставляет определение, подобное классу, которое похоже на «расширенное» наследование Java на основе классов.Тем не менее, это всего лишь JavaScript, который не имеет классов.

Вместо этого мы имеем объектный литерал, передаваемый методу extends.Это как если бы вы написали этот код:

var config = { tags: [] }</p> <p>var MyModel = Backbone.Model.extends(config);

В этом коде config является литералом объекта, или хэшем, или парой ключ / значение, или ассоциативным массивом.,Какое бы имя вы ни называли, это одна и та же основная идея.В итоге вы получите объект config с атрибутом tags.Значение config.tags представляет собой пустой массив, [], который сам является объектом.

, что возвращает нас к короткому ответу:

Когда вы вызываете extends, чтобы определитьваш объект, вы передаете конфигурацию нового объекта как литерал объекта.Объекты передаются по ссылке, а функция extends передает только ссылку на массив тегов в определение нового типа.

Как отмечали другие, вы можете исправить это, назначив tags функции,Это работает, потому что функция задерживает оценку tags, пока объект не будет создан.Нет ничего нативного в JavaScript, который делает это, но сам Backbone распознает tags как функцию или значение.

6 голосов
/ 02 апреля 2012

«теги» объявляются в Content.prototype - который является общим для всех экземпляров Content. Вам, вероятно, нужно использовать значения по умолчанию: http://backbonejs.org/#Model-defaults. Однако следует отметить, что вы должны использовать функцию (вместо хеша) при определении значений по умолчанию, в противном случае вы по-прежнему сталкиваетесь с той же проблемой при использовании типов, которые передаются по ссылке (например, массив).

var Content = Backbone.Model.extend({
  defaults: function() { 
    return {
      tags: []
    };
  }
});
0 голосов
/ 17 ноября 2012

Как упоминал Дерик Бэйли, проблема заключается в передаче по ссылке.Я решил проблему путем клонирования массива (по существу, с передачей по значению):

var _events = window.active_model.get('events').slice(0);
_events.push({ key: "xxx", value: "yyy" });
window.active_field.set('events', _events);
0 голосов
/ 02 апреля 2012

benpickles является правильным, когда речь идет о моделях Backbone, и способ сделать это в coffeescript в целом состоит в инициализации свойств экземпляра в конструкторе:

class Foo
  constructor: ->
    @bar = []
...