Backbone.js处理属性是数组

时间:2011-06-22 01:06:34

标签: javascript backbone.js

我真的很喜欢Backbone,但我最难做的事情似乎很简单。感谢以下示例的任何帮助。

我有一个模型,Criteria,我想用它来存储我的UI中的一些项目的状态。有一些简单的属性,一个属性是一个ID数组,用于存储用户在UI中选择的标记的ID。

所以,我创建了一个新实例。我在tags数组中添加了一些项目。然后,我想重新开始,创建一个新实例,分配给同一个变量。但是,我的标签数组继续保存我作为第一个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>

我是不是在这里?我是否尝试使用Backbone来实现它的目的?或者我在javascript OO编程中遗漏了一些更通用的东西?

P.S。我最初使用了Backbone标签集合,但是它提出了一系列不同的问题,这些问题与多个集合中引用的Tag模型有关,以及当从任何集合中删除项目时,Backbone的remove方法如何取消设置“集合”引用。另一天,另一个问题。

4 个答案:

答案 0 :(得分:70)

“默认值”也可以是一个功能。

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

当实例化新Criteria时,这将创建一个新数组。 请参阅:http://backbonejs.org/#Model-defaults

答案 1 :(得分:34)

Thom Blake对于为什么它保持数组的相同值是正确的。解决此问题的一个选项是在初始值设定项中设置默认值

        var Criteria = Backbone.Model.extend({

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

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

        });

答案 2 :(得分:13)

在“默认值”下定义“标记”时,您将创建一个新数组并将其设置为该类的默认值。然后,当您创建一个新实例时,它具有相同的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', []})

答案 3 :(得分:3)

要明确的是,Maksym H.提供的最后一个选项无法解决问题。假设所有设置的值都是不可变的,则提供defaults属性。但是,数组是可变的,这意味着它的值可以改变(例如,标签[0] =“你好”可以用标签[0] =“hi there”改变。)

通过使用btford的答案,您正在强制在模型的每个新实例上创建任何可变对象/属性的新实例,因此它永远不会被共享,因为该对象是使用函数范围变量创建的。

同样,Derick Bailey的答案是正确的,它只是使用initialize方法而不是默认方法。