從兩個角度去討論Backbone的寫類方式
- Backbone內部的寫類方式,Backbone自身的類如Model、Collection、View等是如何定義的
- Backbone外部的寫類方式,如何使用Backbone提供的類來定義自己的類
一、Backbone內部的寫類方式
Backbone提供給客戶端程序員的類都是通過 構造函數+原型 的方式寫的,Backbone.Model的代碼大致如下
// 定義構造器 var Model = Backbone.Model = function(attributes, options) { // ... this.set(attrs, options); this.changed = {}; this.initialize.apply(this, arguments); }; // 擴展原型,往原型上添加了很多方法,如Events _.extend(Model.prototype, Events, { // ... });
這種寫法很傳統,Backbone.Collection / Backbone.View / Backbone.Router / Backbone.History 都是通過這種方式定義的。
二、Backbone的外部寫類方式
說外部的寫類方式,不得不提 extend 方法,該方法定義在Backbone.js的底部。不到30行代碼,它是私有的,外部並不能訪問。
也就是說,這個方法只在Backbone內部使用,為其它模塊服務。
其實這個說法不嚴謹,雖然extend不能直接訪問,但它通過僅一行代碼
Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
轉身變為以下方法
- Backbone.Model.extend
- Backbone.Collection.extend
- Backbone.View.extend
- Backbone.Router.extend
- Backbone.History.extend
這時,外部還是可以訪問得到。
在一個閉包內,寫一個私有的函數,然后把該函數賦值給多個類或類原型。這些寫法並不少見,這樣寫節省了內存,函數實例其實只有一份。
此外,不要把這里的extend 和 _.extend 搞混了。_.extend是underscore提供的較底層的方法,用來Mixin對象。這里的extend則是用來寫類。
介紹下extend
- 它接受兩個參數,都是對象類型
- 它返回一個類(構造器,函數),怎么叫都行
- 第一個參數的所有屬性、方法都會拷貝到類的原型上(實例對象上)
- 第二個參數的所有屬性、方法都會拷貝的類上(類靜態屬性、方法)
- 第一個參數中如果有constructor屬性,那么最后就返回它,否則返回內部提供的child
- 返回的類有個特殊屬性 __super__。
上面的第六點,使用它很方便的取得父類原型,進而取到父類構造器,進而在子類中去調用父類,這類似於Java里的super關鍵字。
拿示例詳細說說
1. 兩個參數,都是對象類型,第一個擴展為原型方法,第二個擴展為類方法
var instanceObj = { name: '', getName: function() {}, setName: function(name) {} } var classObj = { trim: function(str) {}, mix: function() {} } // 生成一個新類CustomModel,它具有Backbone.Model的所有方法 var CustomModel = Backbone.Model.extend(instanceObj, classObj) // instanceObj屬性都拷貝到了CustomModel.prototype 上 _.each(['name','getName', 'setName'], function(attr) { console.log(attr in CustomModel.prototype) }) // classObj屬性都拷貝到了 CustomModel 上 _.each(['trim','mix'], function(attr) { console.log(attr in CustomModel) })
2. 參數中如果有constructor屬性,那么最后就返回它,否則返回內部提供的child
這實際上告訴使用者可以自定義構造器,而不使用內部的child。
function MyConstructor(name, age) { this.name = name; this.age = age; } var CustomModel = Backbone.Model.extend({ constructor: MyConstructor, getName: function(){}, setName: function(){} }) var m1 = new CustomModel('John', 30) console.log(m1.constructor === MyConstructor) // true
3. 返回的類有個特殊屬性 __super__,用它很方便的取得父類原型,進而取到父類構造器,最后在子類中去調用父類。
function Person(name, age) { this.name = name this.age = age } Person.extend = Backbone.Model.extend // 把Backbone的extend拿出來用,O(∩_∩)O~ function ManConstructor(name, age) { ManConstructor.__super__.constructor.call(this, name, age) // 調用父類構造器 this.gender = 'male' } var Man = Person.extend({ constructor: ManConstructor }) var man = new Man('John', 30) console.log(man) // ManConstructor { name="John", age=30, gender="male"}
總結下Backbone的寫類方式
Backbone內部的寫類方式是 構造函數+原型。外部寫類則是通過extend,寫類和繼承同時存在。
1. 通過Model(View/Router等)的extend方法寫類,產生的類直接繼承了Model(View/Router等)
2. 如果寫的類不是Backbone提供的類,那么可以象3那樣,把extend方法拿出來
使用Backbone開發,多數時候都采用方式1,它強制要求把代碼分為了幾層,一些實用工具函數由underscore提供。
如果是瀏覽器端開發,DOM及HTTP通訊操作一般由jQuery或zepto等提供。你寫的代碼幾乎都集中在業務處理,無非就是模型(Model)、集合(Collection)、視圖(View)、路由(Router)、歷史管理(History)。
相關: