javascript Backbone.js 处理数组属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6433795/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 20:39:49  来源:igfitidea点击:

Backbone.js Handling of Attributes That Are Arrays

javascriptbackbone.js

提问by Kevin

I really like Backbone, but I am having the hardest time doing what would seem to be simple things. I appreciate any help with the following example.

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

I have a model, Criteria, that I want to use to store the state of some items in my UI. there are a couple simple attributes, and one attribute that is an array of IDs used to store the IDs of tags the user has selected in the UI.

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

So, I create a new instance. I add some items to the tags array. Then, I want to start fresh, create a new instance, assigned to the same variable. But, my tags array continues to hold information I added to it as a part of the first instance of Criteria.

所以,我创建了一个新实例。我向标签数组添加了一些项目。然后,我想重新开始,创建一个新实例,分配给相同的变量。但是,我的标签数组继续保存我作为第一个 Criteria 实例的一部分添加到其中的信息。

I have documented the test case below.

我已经记录了下面的测试用例。

<!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>

Am I just way off the mark here? Am I trying to use Backbone for things it was not intended? Or am I missing something more general in javascript OO programming?

我是不是有点跑题了?我是否试图将 Backbone 用于非预期用途?还是我在 javascript OO 编程中遗漏了一些更一般的东西?

P.S. I originally used a Backbone collection of tags, but that presented a whole different set of issues relating to having a Tag model referenced in multiple collections and how Backbone's remove method unsets the "collection" reference when an item is removed from any collection. Another day, another issue.

PS 我最初使用标签的 Backbone 集合,但这提出了一组完全不同的问题,这些问题涉及在多个集合中引用标签模型,以及当从任何集合中删除项目时,Backbone 的 remove 方法如何取消设置“集合”引用。改天,另一个问题。

采纳答案by Derick Bailey

Thom Blake is right about why it's keeping the same values for the array. one option for solving this is to set the default value in the initializer

Thom Blake 正确地解释了为什么它为数组保留相同的值。解决此问题的一种选择是在初始化程序中设置默认值

        var Criteria = Backbone.Model.extend({

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

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

        });

回答by btford

"defaults" can also be a function.

“默认值”也可以是一个函数。

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

This would create a new array when a new Criteria is instantiated. See: http://backbonejs.org/#Model-defaults

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

回答by Tamzin Blake

When you define 'tags' under 'defaults', you create a new Array and set that to the default value for that class. Then, when you create a new instance, it has the same Array reference, which still has the things you pushed into it.

当您在 'defaults' 下定义 'tags' 时,您将创建一个新数组并将其设置为该类的默认值。然后,当您创建一个新实例时,它具有相同的 Array 引用,其中仍然包含您推入其中的内容。

Rather than setting a default value for tags, you should be able to just set it to []before you use it the first time:

您应该能够[]在第一次使用之前将其设置为,而不是为标签设置默认值:

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', []})

回答by Chris M

To be clear, the last option provided by Maksym H. will not solve the problem. The defaults property is provided assuming all of the values set are immutable. An array, however, is mutable, meaning its value can be changed (e.g. tags[0] = "hello" can be changed with tags[0] = "hi there").

需要明确的是,Maksym H. 提供的最后一个选项不会解决问题。假设所有设置的值都是不可变的,则提供 defaults 属性。然而,数组是可变的,这意味着它的值可以改变(例如,tags[0] = "hello" 可以用 tags[0] = "hi there" 改变)。

By using btford's answer, you are forcing a new instance of any mutable object/property to be created on every new instance of the model, so it is never shared, because the object is created with a function scoped variable.

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

Similarly, Derick Bailey's answer is correct, it just uses the initialize method instead of the defaults method.

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