Подтвердить что ты не робот

Backbone.js Обработка атрибутов, которые являются массивами

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

У меня есть модель, Criteria, которую я хочу использовать для хранения состояния некоторых элементов в моем пользовательском интерфейсе. существует несколько простых атрибутов и один атрибут, который представляет собой массив идентификаторов, используемых для хранения идентификаторов тегов, выбранных пользователем в пользовательском интерфейсе.

Итак, я создаю новый экземпляр. Я добавляю некоторые элементы в массив тегов. Затем я хочу начать новый, создать новый экземпляр, назначенный той же переменной. Но массив моих тегов продолжает хранить информацию, которую я добавил к ней, как часть первого экземпляра критериев.

Я зарегистрировал тестовый пример ниже.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Test</title>
    <script src="Scripts/Libraries/jquery-1.6.1.js" type="text/javascript"></script>
    <script src="Scripts/Libraries/underscore.js" type="text/javascript"></script>
    <script src="Scripts/Libraries/backbone.js" type="text/javascript"></script>

    <script language="javascript" type="text/javascript">

        $(function () {

            // Simple model to hold some state about my UI.
            var Criteria = Backbone.Model.extend({

                defaults: {
                    "status": "Normal",
                    "priority": "Normal",
                    "tags": new Array()
                }

            });

            // Create new criteria.
            window.criteria = new Criteria();

            // The length of the tags array should be 0. PASSES
            console.log("Expect 0: Actual " + window.criteria.get("tags").length);

            // Add a tag id to the tags array.
            window.criteria.get("tags").push(5); // Tag with ID of 5.

            // The length of the tags array should be 1. PASSES
            console.log("Expect 1: Actual " + window.criteria.get("tags").length);

            // Create a new instance of criteria.
            window.criteria = new Criteria();

            // The length of the tags array should be 0. FAILS
            // CONFUSED. I thought this is now a new instance with a new set of attributes.
            // Why does the tags collection still have an item in it.
            console.log("Expect 0: Actual " + window.criteria.get("tags").length);

            // OK. So, I will call the clear method on the model. This is supposed to remove all attributes
            // from the model.
            // Then, I will create it again.
            window.criteria.clear();
            window.criteria = new Criteria();

            // The length of the tags array should be 0. FAILS. Still 1.
            console.log("Expect 0: Actual " + window.criteria.get("tags").length);

            // ARGH!
            console.log("HELP!");

        });

    </script>

</head>
<body>
    <h1>Test</h1>
    <p>Backbone test page.</p>
</body>
</html>

Я просто в стороне от знака здесь? Я пытаюсь использовать Магистраль для вещей, которые она не предназначала? Или я пропускаю что-то более общее в программировании OO javascript?

P.S. Первоначально я использовал коллекцию тегов Backbone, но это представляло собой целый ряд проблем, связанных с тем, что модель тегов упоминается в нескольких коллекциях и как метод удаления Backbone отключает ссылку "коллекция", когда элемент удаляется из любой коллекции. Еще один день, еще одна проблема.

4b9b3361

Ответ 1

Thom Blake прав, почему он сохраняет одни и те же значения для массива. одним из вариантов решения этого является установка значения по умолчанию в инициализаторе

        var Criteria = Backbone.Model.extend({

            defaults: {
                "status": "Normal",
                "priority": "Normal"
            },

            initialize: function(){
              if( !this.get('tags') ){ 
                this.set({tags: new Array()});
              }
            }

        });

Ответ 2

"defaults" также может быть функцией.

var Criteria = Backbone.Model.extend({
    defaults: function () {
        return {
            "status": "Normal",
            "priority": "Normal",
            "tags": new Array()
        }
    }
});

Это создаст новый массив, когда будет создан новый критерий. См.: http://backbonejs.org/#Model-defaults

Ответ 3

Когда вы определяете "теги" в разделе "defaults", вы создаете новый массив и устанавливаете значение по умолчанию для этого класса. Затем, когда вы создаете новый экземпляр, он имеет ту же ссылку на Array, в которой все еще есть то, что вы в нее вложили.

Вместо того, чтобы устанавливать значение по умолчанию для тегов, вы должны просто установить его на [], прежде чем использовать его в первый раз:

window.criteria = new Criteria()
window.criteria.set({'tags', []})  //you can use new Array() if you want
window.criteria.get('tags').push(5)

window.criteria = new Criteria()
console.log(window.criteria.get('tags'))   //should be undefined
window.criteria.set({'tags', []})

Ответ 4

Чтобы быть ясным, последний вариант, предоставленный Максимом Х., не решит проблему. Свойство defaults предоставляется при условии, что все установленные значения являются неизменяемыми. Массив, однако, изменен, то есть его значение может быть изменено (например, теги [0] = "привет" могут быть изменены с помощью тегов [0] = "hi there" ).

Используя ответ btford, вы создаете новый экземпляр любого изменяемого объекта/свойства, который должен быть создан на каждом новом экземпляре модели, поэтому он никогда не используется совместно, поскольку объект создается с переменной области действия.

Аналогично, ответ Derick Bailey правильный, он просто использует метод initialize вместо метода по умолчанию.