Backbone源碼分析(一)

  距離上一篇博客有一段時間了,期間各類雜事縈繞。最主要的一件是,當我差很少將整個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

相關文章
相關標籤/搜索