backbone源碼學習筆記(一)

backbone源碼學習筆記(一)

1、整體結構

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
      root.Backbone = factory(root, exports, _, $);
    });
  } else if (typeof exports !== 'undefined') {
    var _ = require('underscore');
    factory(root, exports, _);
  } else {
    root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$));
  }

}(this, function(root, Backbone, _, $) {
    ... //Backbone代碼
    return Backbone;
}));

主要是用當即執行函數造成單獨的做用域,避免污染全局空間,傳入了做用域和Backbone的函數,閉包內部首先對amd和cmd模塊化進行查詢和處理,若是不支持模塊化,就把該函數返回給root.Backbone,該函數接受四個參數,分別是root,root指向上下文(通常是window對象);Backbone(傳入空的對象);underscore;及類jQuery的庫。函數的返回值是Backbone對象,這樣執行root.backbone時就會返回Backbone對象,從而可使用root.backbone.Model等等Backbone內部的對象和方法。javascript

2、extend函數

Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;

Backbone的全部模塊都有extend靜態方法,該方法用來建立一個繼承對應模塊的全部默認方法和屬性的構造函數,並支持傳入本身的原型屬性和靜態屬性。java

var extend = function(protoProps, staticProps) {
    // parent指向this,也就是對應的模塊構函數 
    var parent = this;
    var child;
    // 若是傳進來的原型屬性具備構造函數,就把其賦給child,不然新建構造函數
    if (protoProps && _.has(protoProps, 'constructor')) {
      child = protoProps.constructor;
    } else {
      // 繼承父元素的自己的屬性
      child = function(){ return parent.apply(this, arguments); };
    }
    // 用underscore的extend方法將父元素的靜態屬性及傳進來的靜態屬性克隆給child的靜態屬性
    _.extend(child, parent, staticProps);
    // 借用surrogate一個空的構造函數來繼承父元素的原型屬性,這樣子元素的原型中不會繼承父元素自己的屬性
    var Surrogate = function(){ this.constructor = child; };
    Surrogate.prototype = parent.prototype;
    child.prototype = new Surrogate;

     // 將新傳進的原型屬性添加到子元素的原型上
    if (protoProps) _.extend(child.prototype, protoProps);
    // 存儲父元素的原型
    child.__super__ = parent.prototype;
    // 返回子類
    return child;
  };

3、Model模塊

  • Model 模塊主要用來對數據進行增刪查換、保存上傳等操做,封裝了一些經常使用的屬性和方法。
// 省略部分代碼
var Model = Backbone.Model = function(attributes, options) {
    // 數據對象存放的對象
    this.attributes = {};
    // 肯定模型的集合對象
    if (options.collection) this.collection = options.collection;
    if (options.parse) attrs = this.parse(attrs, options) || {};
    // 把傳進來的attributes及默認屬性合併
    attrs = _.defaults({}, attrs, _.result(this, 'defaults'));
    // 設置屬性
    this.set(attrs, options);
    // 存放改變過的數據對象
    this.changed = {};
    // 初始化函數(須要用自定義覆蓋該函數)
    this.initialize.apply(this, arguments);
  };
  • 主要方法
_.extend(Model.prototype, Events, {
// 主要方法...
});
// 服務器上傳數據
sync: function() {
      return Backbone.sync.apply(this, arguments);
    },
// 根據屬性名取出數據對象裏的屬性值
    get: function(attr) {
      return this.attributes[attr];
    },
// 刪除屬性(刪除屬性是經過將屬性設置爲void 0,並傳入Unset:true,經過set方法來刪除的)
unset: function(attr, options) {
      return this.set(attr, void 0, _.extend({}, options, {unset: true}));
},
// 刪除該模型中的全部屬性,返回this
clear: function(options) {
      var attrs = {};
      for (var key in this.attributes) attrs[key] = void 0;
      return this.set(attrs, _.extend({}, options, {unset: true}));
},
// 返回changed對象中是否有該屬性的布爾值,判斷一個屬性是否被更改過
hasChanged: function(attr) {
      if (attr == null) return !_.isEmpty(this.changed);
      return _.has(this.changed, attr);
    },
// 返回某屬性改變以前的值
previous: function(attr) {
   if (attr == null || !this._previousAttributes) return null;
   return this._previousAttributes[attr];
},

// 返回某屬性改變以前的值的副本
previousAttributes: function() {
   return _.clone(this._previousAttributes);
},

// 返回該模型的具備相同屬性的新實例。
clone: function() {
  return new this.constructor(this.attributes);
},
  • 最重要的set方法:刪除屬性,保存屬性,保存更改的屬性,觸發事件都是經過set方法來完成 的
set: function(key, val, options) {
      var attr, attrs, unset, changes, silent, changing, prev, current;
      if (key == null) return this;

      // Handle both `"key", value` and `{key: value}` -style arguments.
      // 處理傳入的參數是對象鍵值對形式和單個參數形式的兩種狀況
      if (typeof key === 'object') {
        attrs = key;
        // 第一個參數是對象,則第二個參數是配置對象
        options = val;
      } else {
        // 不然創建空對象傳入鍵值
        (attrs = {})[key] = val;
      }
      // 初始化options
      options || (options = {});

      // 驗證參數是不是有效的屬性鍵值對
      if (!this._validate(attrs, options)) return false;

      // 從options中提取配置參數
      unset           = options.unset;
      // 判斷是否須要觸發change事件,值爲true時不觸發
      silent          = options.silent;
      // 改變的數組
      changes         = [];
      // 布爾值,是否正在改變(默認爲false)
      changing        = this._changing;
      // 開始設置. _changing對象設置爲ture
      this._changing  = true;

      if (!changing) {
      // 若是改動完成,則將當前的屬性保存到previous對象中
        this._previousAttributes = _.clone(this.attributes);
        this.changed = {};
      }
      current = this.attributes, prev = this._previousAttributes;

      // Check for changes of `id`.
      if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];

      // 循環傳入的屬性對象
      for (attr in attrs) {
        val = attrs[attr];
        // 若是傳入的值和數據庫中的值不相等,則向changes(須要改變)數組傳入該屬性名
        if (!_.isEqual(current[attr], val)) changes.push(attr);
        // 若是傳入的值和previousAttributes中的值不相等,則向changed(已改變)對象傳入該屬性,不然則刪除changed對象中的該屬性
        if (!_.isEqual(prev[attr], val)) {
          this.changed[attr] = val;
        } else {
          delete this.changed[attr];
        }
        // 若是unset(刪除屬性)爲true,則是刪除屬性,不然則設置新的屬性值
        unset ? delete current[attr] : current[attr] = val;
      }

      // 觸發事件
      if (!silent) {
        if (changes.length) this._pending = options;
        for (var i = 0, length = changes.length; i < length; i++) {
          this.trigger('change:' + changes[i], this, current[changes[i]], options);
        }
      }

    
      return this;
    },
相關文章
相關標籤/搜索