javascript Backbone框架学习

原文出自http://www.css88.com/doc/backbone/

//1.简介
/**
 * Backbone.js为复杂WEB应用程序提供模型(models)、集合(collections)、视图(views)的结构。
 * 其中模型用于绑定键值数据和自定义事件;
 * 集合附有可枚举函数的丰富API;
 * 视图可以声明事件处理函数,并通过RESRful JSON接口连接到应用程序。
 *
 * 意义:
 * 在用javaScript来创建web项目时,Backbone试图定义一组最小而高效的集合,
 * 包括了数据结构(models(模型) 和 collections(集合))和用户接口(views(视图) 和 URLS)。
 * 在web开发环境里,到处都是框架(帮你写好了一切),不过这些库需要你的网站在构建的时候符合该框架的样子,风格,默认的行为。
 * 但是,Backbone还是作为一个工具,让你可以随心所欲的设计你的网站。
 * */

//2.事件
/**
 *  Events 是一个可以融合到任何对象的模块,
 *  给予 对象绑定和触发自定义事件的能力.
 *  Events 在绑定之前 不需要声明, 并且还可以传递参数
 * */
js代码示例
var object = {};
_.extend(object,Backbone.Events);//给object对象扩展Backbone事件
object.on("alert",function(msg){
    alert("Triggered "+msg);
});
object.trigger("alert", "an event");
//应用举例
/**
 * 可以定义一个事件调度程序,然后在你应用的不同地方调用
 * */
js代码示例
var dispatcher = _.clone(Backbone.Events);
/**
 * (1).on 别名 bind
 * 形式:object.on(event,callback,[context]);
 * 在 object 上绑定一个callback回调函数。
 * 只要event触发,该回调函数就会调用。
 * 如果你的一个页面含有大量的不同时间,我们约定使用冒号来为事件添加 命名空间 俗成地使用冒号来命名:"poll:start", 或 "change:selection"。
 * 事件字符串也可能是用空格分隔的多个事件列表(愚人码头注:即可以同时绑定多个事件,事件用空格分隔)...
 * */
js代码示例
book.on("change:title change:author",...);
/**
 * 当回调函数被调用时,通过可选的第三个参数可以为this提供一个context(上下文)值:model.on('change', this.render, this)
 *(愚人码头注:即回调函数中的This,指向传递的第三个参数)。
 * */
/**
 * 当回调函数被绑定到特殊"all"事件时,任何事件的发生都会触发该回调函数,回调函数的第一个参数会传递该事件的名称。
 * 举个例子,将一个对象的所有事件代理到另一对象:
 * */
js代码示例
proxy.on("all",function(eventName){
    object.trigger(eventName);
});
/**
 * 所有Backbone事件方法还支持事件映射的语法, 作为可惜的位置参数:
 * */
js代码示例
book.on({
    "change:title": titleView.update,
    "change:author": authorPane.update,
    "destroy": bookView.remove
});

/**
 * (2).off 别名 unbind
 * 形式:object.off([event], [callback], [context]);
 * 从 object 对象移除先前绑定的 callback 函数。
 * 如果没有指定context(上下文),所有上下文下的这个回调函数将被移除。
 * 如果没有指定callback,所有绑定这个事件回调函数将被移除;
 * 如果没有指定event,所有事件的回调函数会被移除。.
 * */
js代码示例
// Removes just the `onChange` callback.
object.off("change", onChange);
// Removes all "change" callbacks.
object.off("change");
// Removes the `onChange` callback for all events.
object.off(null, onChange);
// Removes all callbacks for `context` for all events.
object.off(null, null, context);
// Removes all callbacks on `object`.
object.off();
/**
 * 需要注意的是,调用 model.off(),
 * 例如,这确实会删除model(模型)上所有的事件—包括Backbone内部用来统计的事件。
 * */

/**
 * (3).trigger
 * 形式:object.off([event], [callback], [context]);
 * object.trigger(event, [*args])
 * 触发给定 event或用空格隔开的事件的回调函数。后续传入 trigger 的参数会传递到触发事件的回调函数里。
 * */

/**
 * (4).once
 * 形式:object.once(event, callback, [context])
 * 用法跟on很像,区别在于绑定的回调函数触发一次后就会被移除(愚人码头注:只执行一次)。简单的说就是“下次不在触发了,用这个方法”。
 * */

/**
 * (5).listenTo
 * 形式:object.listenTo(other, event, callback)
 * 让 object 监听 另一个(other)对象上的一个特定事件。
 * 不使用other.on(event, callback, object),
 * 而使用这种形式的优点是:listenTo允许 object来跟踪这个特定事件,
 * 并且以后可以一次性全部移除它们。callback总是在object上下文环境中被调用。
 */
js代码示例
view.listenTo(model, 'change', view.render);

/**
 * (6).stopListening
 * 形式:object.stopListening([other], [event], [callback]);
 * 让 object 停止监听事件。如果调用不带参数的stopListening,可以移除 object 下所有已经registered(注册)的callback函数...,
 * 或者只删除指定对象上明确告知的监听事件,或者一个删除指定事件,或者只删除指定的回调函数。
 * */
js代码示例
view.stopListening();
view.stopListening(model);

/**
 * (7).listenToOnce
 * 形式:object.listenToOnce(other, event, callback)
 * 用法跟 listenTo 很像,但是事件触发一次后callback将被移除。
 * */

/**Catalog of Events(事件目录)
 * 下面是Backbone 内置事件的完整列表,带有参数。
 * 你也可以在Models(模型),Collection(集合),Views(视图)上自由地触发这些事件,只要你认为合适。 收藏和意见,你认为合适。
 * Backbone 对象本身混入了Events,并且可用于触发任何全局事件,只要您的应用程序的需要。
 * "add" (model, collection, options) — 当一个model(模型)被添加到一个collection(集合)时触发。
 * "remove" (model, collection, options) — 当一个model(模型)从一个collection(集合)中被删除时触发。
 * "reset" (collection, options) — 当该collection(集合)的全部内容已被替换时触发。
 * "sort" (collection, options) — 当该collection(集合)已被重新排序时触发。
 * "change" (model, options) — 当一个model(模型)的属性改变时触发。
 * "change:[attribute]" (model, value, options) — 当一个model(模型)的某个特定属性被更新时触发。
 * "destroy" (model, collection, options) —当一个model(模型)被destroyed(销毁)时触发。
 * "request" (model_or_collection, xhr, options) — 当一个model(模型)或collection(集合)开始发送请求到服务器时触发。
 * "sync" (model_or_collection, resp, options) — 当一个model(模型)或collection(集合)成功同步到服务器时触发。
 * "error" (model_or_collection, resp, options) — 当一个model(模型)或collection(集合)的请求远程服务器失败时触发。
 * "invalid" (model, error, options) — 当model(模型)在客户端 validation(验证)失败时触发。
 * "route:[name]" (params) —  当一个特定route(路由)相匹配时通过路由器触发。
 * "route" (route, params) — 当任何一个route(路由)相匹配时通过路由器触发。
 * "route" (router, route, params) — 当任何一个route(路由)相匹配时通过history(历史记录)触发。
 * "all" — 所有事件发生都能触发这个特别的事件,第一个参数是触发事件的名称。
 * 一般来说,事件触发(例如model.set,collection.add或者其他事件)后就会执行回调函数,
 * 但是如果你想阻止回调函数的执行,你可以传递{silent: true}作为参数。
 * 很多时候,这是一个好的方法。通过在回调函数里传输一个特定的判断参数,会让你的程序更加出色。
 * 一般而言,事件触发(model.set, collection.add,等等...)后就会调用一个函数,但是如果你想阻止事件被触发,
 * 您可以传递{silent: true}作为一个选项。注意,这中情况很少, 甚至从来没有, 一个好主意。
 * 通过在选项中传递一个特定的标记,回调函数里传输一个特定的判断参数 并且选择忽略,会让你的程序更加出色。
 */

//3.Backbone.Model(模型)
/**
 * Models(模型)是任何Javascript应用的核心,包括数据交互及与其相关的大量逻辑: 转换、验证、计算属性和访问控制。
 * 你可以用特定的方法扩展 Backbone.Model,Model 也提供了一组基本的管理变化的功能。
 * 下面的示例演示了如何定义一个模型,包括自定义方法、设置属性、以及触发该属性变化的事件。
 * 一旦运行此代码后,sidebar在浏览器的控制台就可用,这样你就可以充分发挥了。
 * */
js代码示例
var Siderbar = Backbone.Medol.extend({
    promptColor:function(){
        var cssColor = prompt("Please enter a CSS color:");
        this.set({
   color:cssColor});
    }
});
window.sidebar = new Siderbar;
sidebar.on('change:color',function(model,color){
    $('#sidebar').css({
   background:color});
});
sidebar.set({
   color:'white'});
sidebar.promptColor();

/**
 * (1).extend
 * 形式:Backbone.Model.extend(properties, [classProperties])
 * 要创建自己的 Model 类,你可以扩展 Backbone.Model 并提供实例 properties(属性) ,
 * 以及可选的可以直接注册到构造函数的classProperties(类属性)。
 * extend 可以正确的设置原型链,因此通过 extend 创建的子类 (subclasses) 也可以被深度扩展。
 * */
js代码示例
var Note = Backbone.Model.extend({
    initialize:function(){},
    author:function(){},
    coordinates:function(){},
    allowedToEdit:function(account){
        return true;
    }
});
var PrivateNode = Node.extend({
    allowedToEdit:function(account){
        return account.owns(this);
    }
});
/**
*父类(super) 的简述:Javascript没有提供一种直接调用父类的方式 — 如果你要重载原型链中上层定义的同名函数,
* 如 set, 或 save , 并且你想调用父对象的实现,这时需要明确的调用它,类似这样:
 */
js示例代码
var Note = Backbone.Model.extend({
    set: function(attributes, options) {
        Backbone.Model.prototype.set.apply(this, arguments);
    }
});

/**
 * (2).constructor / initializenew
 * 形如: Model([attributes], [options])
 * 当创建model实例时,可以传入 属性 (attributes)初始值,
 * 这些值会被 set (设置)到 model。 如果定义了 initialize 函数,该函数会在model创建后执行。
 * */
js代码示例
new Book({
    title: "One Thousand and One Nights",
    author: "Scheherazade"
});
//在极少数的情况下,你可能需要去重写 constructor ,它可以让你替换你的model的实际构造函数。
js代码示例
var Library = Backbone.Model.extend({
    constructor: function() {
        this.books = new Books();
        Backbone.Model.apply(this, arguments);
    },
    parse: function(data, options) {
        this.books.reset(data.books);
        return data.library;
    }
});
/**如果你传入{collection: ...} ,这个 options表示这个model属于哪个collection,且用于计算这个model的url。
 * 否则model.collection 这个属性会在你第一次添加model到一个collection的时候被自动添加。 需要注意的是相反的是不正确的,
 * 因为传递这个选项给构造函数将不会自动添加model到集合。有时这个是很有用的。
 * 如果{parse: true}被作为一个option选项传递, attributes将在 set到model之前首先通过parse被转换。
 * */

/**(3).get
 * 形如:model.get(attribute)
 * 从当前model中获取当前属性(attributes)值,比如: note.get("title")*/

/**
 * (4).set
 * 形如:model.set(attributes, [options])
 * 向model设置一个或多个hash属性(attributes)。如果任何一个属性改变了model的状态,在不传入 {silent: true} 选项参数的情况下,
 * 会触发 "change" 事件,更改特定属性的事件也会触发。 可以绑定事件到某个属性,例如:change:title,及 change:content。
 * */
js代码示例
note.set({
   title: "March 20", content: "In his eyes she eclipses..."});
book.set("title", "A Scandal in Bohemia");

/**
 * (5).escape
 * 形如:model.escape(attribute)
 * 与 get 类似,只是返回的是HTML转义后版本的model属性值。如果从model插入数据到HTML,
 * 使用 escape 取数据可以避免 XSS 攻击。
 * */
js示例代码
var hacker = new Backbone.Model({
    name: ""
});
alert(hacker.escape('name'));

/**
 * (6).has
 * 形如:model.has(attribute)
 * 属性值为非 null 或非 undefined 时返回 true。
 * */
js示例代码
if (note.has("title")) {
}

/**
 * (7).unset
 * 形如:model.unset(attribute, [options])
 * 从内部属性散列表中删除指定属性(attribute)。 如果未设置 silent 选项,会触发 "change" 事件。
 * */

/**
 * (8).clear
 * 形如:model.clear([options])
 * 从model中删除所有属性, 包括id属性。 如果未设置 silent 选项,会触发 "change" 事件。
 * */

/**
 * (9).id
 * 形如:model.id
 * id是model的特殊属性,可以是任意字符串(整型 id 或 UUID)。在属性中设置的 id 会被直接拷贝到model属性上。
 * 我们可以从集合(collections)中通过 id 获取model,另外 id 通常用于生成model的 URLs。
 * */

/**
 * (10).id
 * 形如:model.id
 * id是model的特殊属性,可以是任意字符串(整型 id 或 UUID)。在属性中设置的 id 会被直接拷贝到model属性上。
 * 我们可以从集合(collections)中通过 id 获取model,另外 id 通常用于生成model的 URLs。
 * */

/**
 * (11).idAttribute
 * 形如:model.idAttribute
 * 一个model的唯一标示符,被储存在 id 属性下。如果使用一个不同的唯一的key直接和后端通信。
 * 可以设置Model的 idAttribute 到一个从key到 id 的一个透明映射中。
 * */
js示例代码
var Meal = Backbone.Model.extend({
    idAttribute: "_id"
});
var cake = new Meal({ _id: 1, name: "Cake" });
alert("Cake id: " + cake.id);

cid
model.cid
model的特殊属性,cid 或客户 id 是当所有model创建时自动产生的唯一标识符。 客户 ids 在model尚未保存到服务器之前便存在,
此时model可能仍不具有最终的 id, 但已经需要在用户界面可见。

attributes
model.attributes
attributes 属性是包含模型状态的内部散列表 — 通常(但不一定)JSON对象的形式表示在服务器上模型数据 。
它通常是数据库中一个行的简单的序列,但它也可以是客户端的计算状态。
建议采用 set 更新 attributes而不要直接修改。  如果您想检索和获取模型属性的副本, 用 _.clone(model.attributes) 取而代之。
由于这样的事实: Events(事件)接受空格分隔事件列表, 但是属性名称不应该包括空格。

changed
model.changed
changed属性是一个包含所有属性的内部散列,自最后 set 已改变。 自最后一组已改变。
请不要直接更新 changed,因为它的状态是由set内部维护。 changed的副本可从changedAttributes获得。

defaults
model.defaults or model.defaults()
defaults 散列(或函数)用于为模型指定默认属性。 创建模型实例时,任何未指定的属性会被设置为其默认值。
js代码示例
var Meal = Backbone.Model.extend({
    defaults: {
        "appetizer":  "caesar salad",
        "entree":     "ravioli",
        "dessert":    "cheesecake"
    }
});
alert("Dessert will be " + (new Meal).get('dessert'));
需要提醒的是,在 Javascript 中,对象是按引用传值的,因此如果包含一个对象作为默认值,它会被所有实例共享。可以定义 defaults为一个函数取代。

toJSON
model.toJSON([options])
返回一个模型的 attributes 浅拷贝副本的 JSON 字符串化形式。 它可用于模型的持久化、序列化,或者发送到服务之前的扩充。
该方法名称比较混乱,因为它事实上并不返回 JSON 字符串, 但这是对 JavaScript API 的 JSON.stringify 实现。
js代码示例
var artist = new Backbone.Model({
    firstName: "Wassily",
    lastName: "Kandinsky"
});
artist.set({
   birthday: "December 16, 1866"});
alert(JSON.stringify(artist));

sync
model.sync(method, model, [options])
使用 Backbone.sync 可以将一个模型的状态持续发送到服务器。 可以自定义行为覆盖。

fetch
model.fetch([options])
通过委托给Backbone.sync从服务器重置模型的状态。返回jqXHR。
如果模型从未填充数据时非常有用, 或者如果你想确保你有最新的服务器状态。
如果服务器的状态不同于当前属性的"change"事件将被触发。
接受 success 和 error回调的选项散列, 这两个回调都可以传递(model, response, options)作为参数。
js代码示例
// 每隔 10 秒从服务器拉取数据以保持频道模型是最新的
setInterval(function() {
    channel.fetch();
}, 10000);

save
model.save([attributes], [options])
通过委托给Backbone.sync,保存模型到数据库(或替代持久化层)。 如果验证成功,返回jqXHR,否则为 false。
attributes散列(如set)应包含你想改变的属性 - 不涉及的键不会被修改 - 但是,该资源的一个完整表示将被发送到服务器。
至于set,你可能会传递单独的键和值,而不是一个哈希值。 如果模型有一个validate方法,并且验证失败, 该模型将不会被保存。
如果模型isNew, 保存将采用"create"(HTTP POST), 如果模型在服务器上已经存在, 保存将采用"update"(HTTP PUT)。
相反,如果你只想将改变属性发送到服务器, 调用model.save(attrs, {
   patch: true})。
你会得到一个HTTP PATCH请求将刚刚传入的属性发送到服务器。
通过新的属性调用save 将立即触发一个"change"事件,一个"request"事件作为Ajax请求开始到服务器,
并且当服务器确认成功修改后立即触发 一个"sync"事件。 如果你想在模型上等待服务器设置新的属性,请传递{wait: true}。
在下面的例子中, 注意我们如何覆盖Backbone.sync的版本,在模型初次保存时接收到 "create"请求,第二次接收到 "update" 请求的。
js代码示例
Backbone.sync = function(method, model) {
    alert(method + ": " + JSON.stringify(model));
    model.set('id', 1);
};
var book = new Backbone.Model({
    title: "The Rough Riders",
    author: "Theodore Roosevelt"
});
book.save();
book.save({
   author: "Teddy"});
save 支持在选项散列表中传入 success error 回调函数, 回调函数支持传入 (model, response, options) 作为参数。
如果服务端验证失败,返回非 200 的 HTTP 响应码,将产生文本或 JSON 的错误内容。
book.save("author", "F.D.R.", {
   error: function(){  }});

destroy
model.destroy([options])
通过委托给Backbone.sync,保存模型到数据库(或替代持久化层)。
通过委托一个HTTP DELETE请求给Backbone.sync破坏服务器上的模型。 返回一个jqXHR对象, 或者如果模型isNew,那么返回false。
选项散列表中接受 success error 回调函数, 回调函数支持传入 (model, response, options) 作为参数。
在模型上触发 "destroy" 事件,该事件将会冒泡到任何包含这个模型的集合中,
一个"request"事件作为Ajax请求开始到服务器, 并且当服务器确认模型被删除后立即触发 一个"sync"事件。
如果你想在集合中删除这个模型前等待服务器相应,请传递{wait: true}。
js代码示例
book.destroy({
   success: function(model, response) {

}});

Underscore 方法 (6)
Backbone 代理了 Underscore.js用来给Backbone.Model提供 6 个对象函数。
这里没有完全记录他们,但你可以看看Underscore文档中全部详情… (愚人码头注:下面链接已经替换成中文文档的地址)
keys
values
pairs
invert
pick
omit
user.pick('first_name', 'last_name', 'email');
chapters.keys().join(', ');

validate
model.validate(attributes, options)
这种方法是未定义的, 如果您有任何可以在JavaScript中执行的代码 并且我们鼓励你用你自定义验证逻辑覆盖它 。
默认情况下validate在save之前调用, 但如果传递了 {validate:true},也可以在set之前调用。
validate方法是通过模型的属性,  选项和set 和 save是一样的。 如果属性是有效的, validate不返回验证任何东西;
如果它们是无效的, 返回一个你选择的错误。 它可以是一个用来显示的简单的字符串错误信息,
或一个以编程方式描述错误的完整错误对象。 如果validate返回一个错误, save不会继续, 并且在服务器上该模型的属性将不被修改。
校验失败将触发"invalid"事件, 并用此方法返回的值设置模型上的validationError属性。
js代码示例
var Chapter = Backbone.Model.extend({
    validate: function(attrs, options) {
        if (attrs.end < attrs.start) {
            return "can't end before it starts";
        }
    }
});
var one = new Chapter({
    title : "Chapter One: The Beginning"
});
one.on("invalid", function(model, error) {
    alert(model.get("title") + " " + error);
});
one.save({
    start: 15,
    end:   10
});
"invalid"事件提供粗粒度的错误信息 在模型或集合层面上是很有用。

validationError
model.validationError
用validate最后验证失败时返回的值。

isValid
model.isValid()
运行validate来检查模型状态。
js代码示例
var Chapter = Backbone.Model.extend({
    validate: function(attrs, options) {
        if (attrs.end < attrs.start) {
            return "can't end before it starts";
        }
    }
});
var one = new Chapter({
    title : "Chapter One: The Beginning"
});
one.set({
    start: 15,
    end:   10
});
if (!one.isValid()) {
    alert(one.get("title") + " " + one.validationError);
}

url
model.url()
返回模型资源在服务器上位置的相对 URL 。
如果模型放在其它地方,可通过合理的逻辑重载该方法。
生成 URLs 的默认形式为:"/[collection.url]/[id]", 如果模型不是集合的一部分,你可以通过指定明确的urlRoot覆盖。
由于是委托到 Collection#url 来生成 URL, 所以首先需要确认它是否定义过,或者所有模型共享一个通用根 URL 时,是否存在 urlRoot 属性。
例如,一个 id 101 的模型,存储在 url "/documents/7/notes" Backbone.Collection 中, 那么该模型的 URL 为:"/documents/7/notes/101"

urlRoot
model.urlRoot or model.urlRoot()
如果使用的集合外部的模型,通过指定 urlRoot 来设置生成基于模型 id 的 URLs 的默认 url 函数。
"[urlRoot]/id"。通常情况下,你不会需要定义这一点。 需要注意的是urlRoot也可以是一个函数。
js示例代码
var Book = Backbone.Model.extend({
   urlRoot : '/books'});
var solaris = new Book({
   id: "1083-lem-solaris"});
alert(solaris.url());

parse
model.parse(response, options)
parse 会在通过 fetch 从服务器返回模型数据,以及 save 时执行。
传入本函数的为原始 response 对象,并且应当返回可以 set 到模型的属性散列表。
默认实现是自动进行的,仅简单传入 JSON 响应。 如果需要使用已存在的 API,或者更好的命名空间响应,可以重载它。
如果使用的3.1版本之前的 Rails 后端,需要注意 Rails's 默认的 to_json 实现已经包含了命名空间之下的模型属性。 对于无缝的后端集成环境禁用这种行为:
ActiveRecord::Base.include_root_in_json = false

clone
model.clone()
返回该模型的具有相同属性的新实例。

isNew
model.isNew()
模型是否已经保存到服务器。 如果模型尚无 id,则被视为新的。

hasChanged
model.hasChanged([attribute])
标识模型从上次 set 事件发生后是否改变过。 如果传入 attribute ,当指定属性改变后返回 true。
注意,本方法以及接下来 change 相关的方法,仅对 "change"事件发生有效。
js示例代码
book.on("change", function() {
    if (book.hasChanged("title")) {
    }
});

changedAttributes
model.changedAttributes([attributes])
只从最后一次set开始检索已改变的模型属性散列(hash),  或者如果没有,返回 false。
作为可选,可以传递外部属性哈希(hash), 返回与该模型不同的属性的哈希(hash)。
这可以用来找出视图的哪些部分应该更新,或者确定哪些需要与服务器进行同步。

previous
model.previous(attribute)
在 "change" 事件发生的过程中,本方法可被用于获取已改变属性的旧值。
js示例代码
var bill = new Backbone.Model({
    name: "Bill Smith"
});
bill.on("change:name", function(model, name) {
    alert("Changed name from " + bill.previous("name") + " to " + name);
});
bill.set({
   name : "Bill Jones"});

previousAttributes
model.previousAttributes()
返回模型的上一个属性的副本。
一般用于获取模型的不同版本之间的区别,或者当发生错误时回滚模型状态。

//4Backbone.Collection(集合)
/**
 * 集合是模型的有序组合,我们可以在集合上绑定 "change" 事件,从而当集合中的模型发生变化时fetch(获得)通知,
 * 集合也可以监听 "add" 和 "remove" 事件, 从服务器更新,并能使用 Underscore.js 提供的方法。
 * 集合中的模型触发的任何事件都可以在集合身上直接触发,所以我们可以监听集合中模型的变化: documents.on("change:selected", ...)
 * */

extend
Backbone.Collection.extend(properties, [classProperties])
通过扩展 Backbone.Collection 创建一个 Collection 类。实例属性参数 properties 以及 类属性参数 classProperties 会被直接注册到集合的构造函数。

model
collection.model
覆盖此属性来指定集合中包含的模型类。可以传入原始属性对象(和数组)来 add, create,和 reset,传入的属性会被自动转换为适合的模型类型。
js示例代码
var Library = Backbone.Collection.extend({
    model: Book
});
//集合也可以包含多态模型,通过用构造函数重写这个属性,返回一个模型。
var Library = Backbone.Collection.extend({
    model: function(attrs, options) {
        if (condition) {
            return new PublicDocument(attrs, options);
        } else {
            return new PrivateDocument(attrs, options);
        }
    }
});

constructor / initializenew 
Backbone.Collection([models], [options])
当创建集合时,你可以选择传入初始的 models 数组。 
集合的 comparator 函数也可以作为选项传入。 传递false作为comparator选项将阻止排序。 
如果定义了 initialize 函数,会在集合创建时被调用。 有几个选项, 如果提供的话,将直接附加到集合上:model 和 comparator。
通过传递null给models选项来创建一个空的集合。
js示例代码
var tabs = new TabSet([tab1, tab2, tab3]);
var spaces = new Backbone.Collection([], {
    model: Space
});

models
collection.models
访问集合中模型的内置的JavaScript 数组。通常我们使用 get, at,或 Underscore方法 访问模型对象,但偶尔也需要直接访问。

toJSON
collection.toJSON([options])
返回集合中包含的每个模型(通过 toJSON) 的属性哈希的数组。
可用于集合的序列化和持久化。本方法名称容易引起混淆,因为它与 JavaScript's JSON API 命名相同。
js示例代码
var collection = new Backbone.Collection([
    {
   name: "Tim", age: 5},
    {
   name: "Ida", age: 26},
    {
   name: "Rob", age: 55}
]);
alert(JSON.stringify(collection));

sync
collection.sync(method, collection, [options])
使用 Backbone.sync来将一个集合的状态持久化到服务器。 可以自定义行为覆盖。

Underscore 方法 (32)
Backbone 代理了 Underscore.js用来给Backbone.Collection提供 6 个对象函数。
这里没有完全记录他们,但你可以看看Underscore文档中全部详情…(愚人码头注:下面链接已经替换成中文文档的地址)
forEach (each)
map (collect)
reduce (foldl, inject)
reduceRight (foldr)
find (detect)
filter (select)
reject
every (all)
some (any)
contains (include)
invoke
max
min
sortBy
groupBy
shuffle
toArray
size
first (head, take)
initial
rest (tail, drop)
last
without
indexOf
lastIndexOf
isEmpty
chain
difference
sample
partition
countBy
indexBy
js示例代码
books.each(function(book) {
    book.publish();
});
var titles = books.map(function(book) {
    return book.get("title");
});
var publishedBooks = books.filter(function(book) {
    return book.get("published") === true;
});
var alphabetical = books.sortBy(function(book) {
    return book.author.get("name").toLowerCase();
});

add
collection.add(models, [options])
向集合中增加一个模型(或一个模型数组),触发"add"事件。  
如果已经定义了model属性, 您也可以通过原始属性的对象让其看起来像一个模型实例。 返回已经添加的(或预先存在的,如果重复)模式。  
传递{at: index}可以将模型插入集合中特定的index索引位置。 
如果您要添加 集合中已经存在的模型 到集合,他们会被忽略, 除非你传递{merge: true}, 
在这种情况下,它们的属性将被合并到相应的模型中, 触发任何适当的"change" 事件。
js示例代码
var ships = new Backbone.Collection;
ships.on("add", function(ship) {
    alert("Ahoy " + ship.get("name") + "!");
});
ships.add([
    {
   name: "Flying Dutchman"},
    {
   name: "Black Pearl"}
]);
请注意,添加相同的模型(具有相同id的模型)到一个集合,一次以上
是空操作。

remove
collection.remove(models, [options])
从集合中删除一个模型(或一个模型数组),并且返回他们。
会触发 "remove" 事件,同样可以使用 silent 关闭。
移除前该模型的index可用作options.index类监听。

reset
collection.reset([models], [options])
每次都是只添加和删除一个模型那没问题, 但有时,你需要改变很多模型,那么你宁愿只更新集合。  
使用reset,将一个新的模型(或属性散列)列表替换集合,最后触发一个但单独的"reset"事件。 
到与模型的新列表替换集合(或属性散列),触发一个单一的“复位”事件在末端。 返回新的模型集合。 
为方便起见, 在一个 "reset"事件中, 任何以前的模型列表可作为options.previousModels。
通过传递null给models选项来清空你的集合。

下面是一个例子 使用reset来引导一个集合在页面初始化时加载, 在Rails应用程序中:
js代码示例

调用collection.reset(),不传递任何模型作为参数 将清空整个集合。

set
collection.set(models, [options])
set方法通过传递模型列表执行一个集合的"smart(智能)"的更新。 如果列表中的一个模型尚不在集合中,那么它将被添加; 
如果模型已经在集合中,其属性将被合并; 并且如果集合包含不存在于列表中的任何模型,他们将被删除。
以上所有将触发相应的"add", "remove", 和 "change"事件。 返回集合中的模型。 如果您想自定义的行为, 你可以设置选项:{add: false}, {remove: false}, 或 {merge: false},将其禁用。
js代码示例
var vanHalen = new Backbone.Collection([eddie, alex, stone, roth]);
vanHalen.set([eddie, alex, stone, hagar]);

get
collection.get(id)
通过一个id,一个cid,或者传递一个model来 获得集合中 的模型。
js代码示例
var book = library.get(110);

at
collection.at(index)
获得集合中指定索引的模型。不论你是否对模型进行了重新排序, at 始终返回其在集合中插入时的索引值。

push
collection.push(model, [options])
在集合尾部添加一个模型。选项和add相同。

pop
collection.pop([options])
删除并且返回集合中最后一个模型。选项和remove相同。

unshift
collection.unshift(model, [options])
在集合开始的地方添加一个模型。选项和add相同。

shift
collection.shift([options])
删除并且返回集合中第一个模型。选项和remove相同。

slice
collection.slice(begin, end)
返回一个集合的模型的浅拷贝副本,使用与原生Array#slice相同的选项。

length
collection.length
与数组类似,集合拥有 length 属性,返回该集合包含的模型数量。

comparator
collection.comparator
默认情况下,集合没有声明 comparator 函数。如果定义了该函数,集合中的模型会按照指定的算法进行排序。 
换言之,被增加模型,会被插入 collection.models中适合的位置。 comparator可以被定义为sortBy(传递带有一个参数的函数),  
作为一个sort(传递一个一个参数函数需要两个参数), 或者作为一个表示属性的字符串进行排序。
"sortBy"比较函数接受一个模型,并且返回一个该模型相对于其他模型的排序数字或字符串值。  
"sort"比较函数接受两个模型,并且,如果第一个模型应该在第二模型个之前,返回-1; 如果他们是同一等级的,返回0;
如果第一个模型应该在第二模型个之后,返回1; 
需要注意的是 Backbone 这两种风格的比较功能的确定 取决于参数个数。所以如果你绑定了比较函数,需要格外小心。
注意即使下面例子中的 chapters 是后加入到集合中的,但它们都会遵循正确的排序:
js代码示例
var Chapter  = Backbone.Model;
var chapters = new Backbone.Collection;
chapters.comparator = 'page';
chapters.add(new Chapter({
   page: 9, title: "The End"}));
chapters.add(new Chapter({
   page: 5, title: "The Middle"}));
chapters.add(new Chapter({
   page: 1, title: "The Beginning"}));
alert(chapters.pluck('title'));
如果以后更改模型属性,带有比较函数的集合不会自动重新排序。 所以你不妨改变模型的属性后调用sort, 这会影响排序。

sort
collection.sort([options])
强制对集合进行重排序。一般情况下不需要调用本函数,因为当一个模型被添加时,
comparator 函数会实时排序。要禁用添加模型时的排序,可以传递{sort: false}给add。
调用sort会触发的集合的"sort"事件。

pluck
collection.pluck(attribute)
从集合中的每个模型中拉取 attribute(属性)。等价于调用 map,并从迭代器中返回单个属性。
js代码示例
var stooges = new Backbone.Collection([
    {
   name: "Curly"},
    {
   name: "Larry"},
    {
   name: "Moe"}
]);
var names = stooges.pluck("name");
alert(JSON.stringify(names));

where
collection.where(attributes)
返回集合中所有匹配所传递 attributes(属性)的模型数组。 对于简单的filter(过滤)比较有用。
js代码示例
var friends = new Backbone.Collection([
    {
   name: "Athos",      job: "Musketeer"},
    {
   name: "Porthos",    job: "Musketeer"},
    {
   name: "Aramis",     job: "Musketeer"},
    {
   name: "d'Artagnan", job: "Guard"},
]);
var musketeers = friends.where({
   job: "Musketeer"});
alert(musketeers.length);

findWhere
collection.findWhere(attributes)
就像where, 不同的是findWhere直接返回匹配所传递 attributes(属性)的第一个模型。

url
collection.url or collection.url()
设置 url 属性(或函数)以指定集合对应的服务器位置。集合内的模型使用 url 构造自身的 URLs。
js代码示例
var Notes = Backbone.Collection.extend({
    url: '/notes'
});
var Notes = Backbone.Collection.extend({
    url: function() {
        return this.document.url() + '/notes';
    }
});

parse
collection.parse(response, options)
每一次调用 fetch 从服务器拉取集合的模型数据时,parse都会被调用。 
本函数接收原始 response 对象,返回可以 added(添加) 到集合的模型属性数组。 默认实现是无需操作的,只需简单传入服务端返回的JSON对象。
如果需要处理遗留API,或者在返回数据定义自己的命名空间,可以重写本函数。
var Tweets = Backbone.Collection.extend({
    // The Twitter Search API returns tweets under "results".
    parse: function(response) {
        return response.results;
    }
});

clone
collection.clone()
返回一个模型列表完全相同的集合新实例。

fetch
collection.fetch([options])
从服务器拉取集合的默认模型设置 ,成功接收数据后会setting(设置)集合。
options 支持 success error 回调函数,两个回调函数接收 (collection, response, options)作为参数。
当模型数据从服务器返回时, 它使用 set来(智能的)合并所获取到的模型, 除非你传递了 {reset: true}, 在这种情况下,集合将(有效地)重置。 
可以委托Backbone.sync 在幕后自定义持久性策略 并返回一个jqXHR。 fetch请求的服务器处理器应该返回模型JSON数组。
js代码示例
Backbone.sync = function(method, model) {
    alert(method + ": " + model.url);
};
var accounts = new Backbone.Collection;
accounts.url = '/accounts';
accounts.fetch();
fetch行为可以通过使用有效的set选项进行定制。 
例如,要获取一个集合,每一个新的模型会得到一个 "add"事件,和每改变现有的模型的 "change"事件,
不删除任何东西: collection.fetch({
   remove: false})
jQuery.ajax选项也可以直接传递作为 fetch选项, 所以要获取一个分页集合的特定页面使用:Documents.fetch({
   data: {
   page: 3}})。
需要注意的是 fetch 不应该被用来在页面加载完毕时填充集合数据 — 所有页面初始数据应当在 bootstrapped 时已经就绪。 
fetch 适用于惰性加载不需立刻展现的模型数据:例如:例如文档中 可切换打开和关闭的选项卡内容。

create
collection.create(attributes, [options])
方便的在集合中创建一个模型的新实例。 相当于使用属性哈希(键值对象)实例化一个模型, 然后将该模型保存到服务器, 创建成功后将模型添加到集合中。 
返回这个新模型。 如果客户端验证失败,该模型将不会被保存, 与验证错误。 为了能正常运行,需要在集合中设置 model 属性。 
create 方法接收键值对象或者已经存在尚未保存的模型对象作为参数。
创建一个模型将立即触发集合上的"add"事件, 一个"request"的事件作为新的模型被发送到服务器, 还有一个 "sync" ”事件,
一旦服务器响应成功创建模型。 如果你想在集合中添加这个模型前等待服务器相应,请传递{wait: true}。
js代码示例
var Library = Backbone.Collection.extend({
    model: Book
});
var nypl = new Library;
var othello = nypl.create({
    title: "Othello",
    author: "William Shakespeare"
});

//5.Backbone.Router(路由)
web应用程序通常需要为应用的重要位置提供可链接,可收藏,可分享的 URLs。 直到最近, 猫点(hash)片段(#page)可以被用来提供这种链接, 
同时随着 History API 的到来,猫点已经可以用于处理标准 URLs (/page)。 Backbone.Router 为客户端路由提供了许多方法,并能连接到指定的动作(actions)和事件(events)。
对于不支持 History API 的旧浏览器,路由提供了优雅的回调函数并可以透明的进行 URL 片段的转换。
页面加载期间,当应用已经创建了所有的路由,需要调用 Backbone.history.start(),或 Backbone.history.start({
   pushState: true}) 来确保驱动初始化 URL 的路由。

extend
Backbone.Router.extend(properties, [classProperties])
开始创建一个自定义的路由类。当匹配了 URL 片段便执行定义的动作,并可以通过 routes 定义路由动作键值对。 请注意,你要避免在路由定义时使用前导斜杠:
js代码示例
var Workspace = Backbone.Router.extend({
    routes: {
        "help":                 "help",    // #help
        "search/:query":        "search",  // #search/kiwis
        "search/:query/p:page": "search"   // #search/kiwis/p7
    },
    help: function() {

    },
    search: function(query, page) {
    }
});

routes
router.routes
routes 将带参数的 URLs 映射到路由实例的方法上(或只是直接的函数定义,如果你喜欢),
这与 View(视图) 的 events hash(事件键值对) 非常类似。 路由可以包含参数, :param,
它在斜线之间匹配 URL 组件。 路由也支持通配符, *splat,可以匹配多个 URL 组件。 路由的可选部分放在括号中(/:optional)。
举个例子,路由 "search/:query/p:page" 能匹配#search/obama/p2 , 这里传入了 "obama" "2" 到路由对应的动作中去了。
路由 "file/*path"可以匹配 #file/nested/folder/file.txt,这时传入动作的参数为 "nested/folder/file.txt"。
路由 "docs/:section(/:subsection)"可以匹配#docs/faq 和 #docs/faq/installing,第一种情况,传入 "faq" 到路由对应的动作中去, 
第二种情况,传入"faq" "installing" 到路由对应的动作中去。
结尾的斜杠会被当作URL的一部分, 访问时会被(正确地)当作一个独立的路由。 
docs 和 docs/将触发不同的回调。 如果你不能避免产生这两种类型的URLs时, 你可以定义一个"docs(/)"来匹配捕捉这两种情况。
当访问者点击浏览器后退按钮,或者输入 URL ,如果匹配一个路由,此时会触发一个基于动作名称的 event, 
其它对象可以监听这个路由并接收到通知。 下面的示例中,用户访问 #help/uploading 将从路由中触发 route:help 事件。
js代码示例
routes: {
    "help/:page":         "help",
        "download/*path":     "download",
        "folder/:name":       "openFolder",
        "folder/:name-:mode": "openFolder"
}
router.on("route:help", function(page) {
    
});

constructor / initializenew 
Router([options])
当创建一个新路由是,你可以直接传入 routes 键值对象作为参数。 如果定义该参数, 它们将被传入 initialize 构造函数中初始化。

router
outer.route(route, name, [callback])
为路由对象手动创建路由,route 参数可以是 routing string(路由字符串) 或 正则表达式。 每个捕捉到的被传入的路由或正则表达式,
都将作为参数传入回调函数(callback)。 一旦路由匹配, name 参数会触发 "route:name" 事件。如果callback参数省略 router[name]将被用来代替。
后来添加的路由可以覆盖先前声明的路由。
js代码示例
initialize: function(options) {
    // Matches #page/10, passing "10"
    this.route("page/:number", "page", function(number){ });
    // Matches /117-a/b/c/open, passing "117-a/b/c" to this.open
    this.route(/^(.*?)\/open$/, "open");
},
open: function(id) {}

navigate
router.navigate(fragment, [options])
每当你达到你的应用的一个点时,你想保存为一个URL,  可以调用navigate以更新的URL。 
如果您也想调用路由功能, 设置trigger选项设置为true。 无需在浏览器的历史记录创建条目来更新URL,  设置 replace选项设置为true。
js代码示例
openPage: function(pageNumber) {
    this.document.pages.at(pageNumber).open();
    this.navigate("page/" + pageNumber);
}

# Or ...

    app.navigate("help/troubleshooting", {
   trigger: true});

# Or ...
    app.navigate("help/troubleshooting", {
   trigger: true, replace: true});

execute
router.execute(callback, args)
这种方法在路由内部被调用,  每当路由和其相应的callback匹配时被执行。 覆盖它来执行自定义解析或包装路由, 例如, 在传递他们给你的路由回调之前解析查询字符串,像这样:

var Router = Backbone.Router.extend({
    execute: function(callback, args) {
        args.push(parseQueryString(args.pop()));
        if (callback) callback.apply(this, args);
    }
});

//6.Backbone.history
History 作为全局路由服务用于处理 hashchange 事件或 pushState,匹配适合的路由,并触发回调函数。 
我们不需要自己去做这些事情 — 如果使用带有键值对的 路由,Backbone.history 会被自动创建。

Backbone 会自动判断浏览器对 pushState 的支持,以做内部的选择。 不支持 pushState 的浏览器将会继续使用基于猫点的 URL 片段,
如果兼容 pushState 的浏览器访问了某个 URL 猫点,将会被透明的转换为真实的 URL。 注意使用真实的 URLs 需要 web 服务器支持直接渲染那些页面,
因此后端程序也需要做修改。 例如,如果有这样一个路由 /document/100,如果浏览器直接访问它, web 服务器必须能够处理该页面。 
趋于对搜索引擎爬虫的兼容,让服务器完全为该页面生成静态 HTML 是非常好的做法 ...但是如果要做的是一个 web 应用,只需要利用 Javascript 和 Backbone 视图将服务器返回的 REST 数据渲染就很好了。

start
Backbone.history.start([options])
当所有的 Routers 创建并设置完毕,调用 Backbone.history.start() 开始监控 hashchange 事件并分配路由。后续调用Backbone.history.start()会抛出一个错误, 
并且Backbone.History.started是一个布尔值,指示是否已经被调用。
需要指出的是,如果想在应用中使用 HTML5 支持的 pushState,只需要这样做:Backbone.history.start({
   pushState : true}) 。
如果你想使用pushState的话, 对于那些本身不支持它的浏览器,需要用整页刷新代替, 您可以添加{hashChange: false}到选项。
如果应用不是基于域名的根路径 /,需要告诉 History 基于什么路径: Backbone.history.start({
   pushState: true, root: "/public/search/"})
当执行后,如果某个路由成功匹配当前 URL,Backbone.history.start() 返回 true。 如果没有定义的路由匹配当前 URL,返回 false。
如果服务器已经渲染了整个页面,但又不希望开始 History 时触发初始路由,传入 silent : true 即可。
因为在Internet Explorer中基于hash的历史记录依赖于