距離上一篇博客有一段時間了,期間各類雜事縈繞。最主要的一件是,當我差很少將整個dojo核心源碼看完,驚訝的發現dojo1.*的設計以是老態龍鍾之象,而我沉溺在dojo中過久,已經不知道前端世界變成了什麼樣。這無異於晴天霹靂,霹的我目瞪口呆、汗流滿面,惶惶不可終日。索性亡羊補牢爲時未晚,這段期間雖有各類煩心事,但還能於百煩之中騰出點時間,看看源碼已是萬中之幸。各類前端類庫如浩瀚星辰,面對它們才能感受到自身技術的淺薄,自身能力的低微。初出茅廬天下無敵,再練三年步履維艱,這就是我當前最真切的體悟。如今的我只能找幾個經典類庫,悉心研究,戒驕戒躁,誠誠懇懇的去學習大牛的代碼,今天爲你們帶來backbone的源碼研究。能力淺薄,不足之處請各位大牛不吝斧正。html
從backbone的整體結構來看,是一個當即執行的函數表達式,參數是一個匿名函數。(function(){})()和(function(){}())的目的是將函數聲明轉換爲函數表達式,消除Js引擎在識別函數聲明和函數表達式上的歧義,除了小括號外還有其餘運算符可以作到,詳細介紹能夠參照這篇文章:js中(function(){…})()當即執行函數寫法理解前端
(function(factory) { //模塊定義 })(function(root, Backbone, _, $) { //Backbone });
模塊處理內容以下:jquery
function(factory) { // Establish the root object, `window` (`self`) in the browser, or `global` on the server. // We use `self` instead of `window` for `WebWorker` support. //拿到當前環境中的全局對象;瀏覽器中爲window,self也是瀏覽器提供的一個全局對象,始終指向window //server端的運行環境則提供global這個全局對象 var root = (typeof self == 'object' && self.self === self && self) || (typeof global == 'object' && global.global === global && global); // Set up Backbone appropriately for the environment. Start with AMD. //若是有amd加載器則將Backbone定義包裝成amd加載器可識別的模塊 if (typeof define === 'function' && define.amd) { //AMD規範定義兩個全局函數define和requrie,而且規定define有個amd屬性,來區分amd的define和普通名爲define的函數 define(['underscore', 'jquery', 'exports'], function(_, $, exports) { // Export global even in AMD case in case this script is loaded with // others that may still expect a global Backbone. root.Backbone = factory(root, exports, _, $); }); // Next for Node.js or CommonJS. jQuery may not be needed as a module. //若是運行在Node端,則將Backbone包裝成CommonJs的模塊 } else if (typeof exports !== 'undefined') { var _ = require('underscore'), $; try { $ = require('jquery'); } catch (e) {} factory(root, exports, _, $); // Finally, as a browser global. //以上兩種狀況都沒有,則以最簡單的執行函數方式,將函數的返回值做爲全局對象Backbone } else { root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$)); } }
factory部分總體結構以下:瀏覽器
function(root, Backbone, _, $) { // Backbone.Events // --------------- // Backbone.Model // -------------- // Backbone.Collection // ------------------- // Backbone.View // ------------- // Backbone.Router // --------------- // Backbone.History // ---------------- // Helpers // ------- }
本篇文章中,咱們簡單學習兩個比較有用的工具方法:noConflict和extend。app
首先介紹noConflict模式。這是jquery發明的使用方法,以後你們爭相相仿。主要原理是由於JavaScript採用的詞法做用域(經過閱讀變量定義在內的少數幾行代碼就能知道變量的做用域),函數的做用域由定義時決定而不是由函數調用時決定的,因此noConflict運行時可以訪問到previousBackbone變量。若是已經有全局的Backbone變量,先將全局的Backbone變量暫存在previousBackbone內,當調用noConflict時,全局的Backbone指向以前暫存在previousBackbone中的Backbone,而返回的this關鍵字指向該factory函數中定義的Backbone對象。函數
// Save the previous value of the `Backbone` variable, so that it can be // restored later on, if `noConflict` is used. var previousBackbone = root.Backbone; // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable // to its previous owner. Returns a reference to this Backbone object. Backbone.noConflict = function() { root.Backbone = previousBackbone; return this; };
下面介紹extend方法,extend方法常見於大多數的JavaScript類庫中,來實現繼承父類創造子類。關於繼承的文章,請看個人這篇文章JavaScript面向對象之我見,這裏直接介紹源碼了。工具
// Helper function to correctly set up the prototype chain for subclasses. // Similar to `goog.inherits`, but uses a hash of prototype properties and // class properties to be extended. //protoProps放置到子類原型上的屬性 //staticProps模擬靜態屬性,直接放置到子類上 var extend = function(protoProps, staticProps) { var parent = this;//利用局部變量保存this關鍵字 var child; // The constructor function for the new subclass is either defined by you // (the "constructor" property in your `extend` definition), or defaulted // by us to simply call the parent constructor. //若是protoProps中有constructor屬性,則將constructor指向的函數做爲構造函數 if (protoProps && _.has(protoProps, 'constructor')) { child = protoProps.constructor; } else {//沒有構造函數,則利用一個默認的函數做爲構造函數。 //基本上屬於組合式繼承 child = function(){ return parent.apply(this, arguments); }; } // Add static properties to the constructor function, if supplied. //underscore中的方法,與常見的mixin函數相似 _.extend(child, parent, staticProps); // Set the prototype chain to inherit from `parent`, without calling // `parent`'s constructor function and add the prototype properties. //將child的原型鏈與parent.prototype關聯。 //_.create函數,的做用相似Object.create,第一個參數是要被繼承的原型對象,第二個參數是要混入到新對象的鍵值對 child.prototype = _.create(parent.prototype, protoProps); child.prototype.constructor = child;//原型中的constructor屬性指向child // Set a convenience property in case the parent's prototype is needed // later. child.__super__ = parent.prototype;//設置一個私有屬性指向父類的原型 return child; };
然後將全部Backbone對外的提供的構造函數的extend屬性都指向上文的extend函數,這樣你們都有了派生子類的功能。學習
// Set up inheritance for the model, collection, router, view and history. Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
以上就是本文的主要內容,稍後將爲你們帶來Model與Collection的解析。ui