1. 云栖社区>
  2. 博客列表>
  3. 正文

Backbone源码分析(一)

木的树 2016-04-22 09:57:07 浏览469 评论0

javascript, backbone

摘要:  距离上一篇博客有一段时间了,期间各种琐事萦绕。最主要的一件是,当我差不多将整个dojo核心源码看完,惊讶的发现dojo1.*的设计以是老态龙钟之象,而我沉溺在dojo中太久,已经不知道前端世界变成了什么样。

 距离上一篇博客有一段时间了,期间各种琐事萦绕。最主要的一件是,当我差不多将整个dojo核心源码看完,惊讶的发现dojo1.*的设计以是老态龙钟之象,而我沉溺在dojo中太久,已经不知道前端世界变成了什么样。这无异于晴天霹雳,霹的我目瞪口呆、汗流满面,惶惶不可终日。索性亡羊补牢为时未晚,这段期间虽有各种烦心事,但还能于百烦之中腾出点时间,看看源码已经是万中之幸。各种前端类库如浩瀚星辰,面对它们才能感觉到自身技术的浅薄,自身能力的低微。初出茅庐天下无敌,再练三年寸步难行,这就是我当前最真切的体悟。现在的我只能找几个经典类库,悉心研究,戒骄戒躁,诚诚恳恳的去学习大牛的代码,今天为大家带来backbone的源码研究。能力浅薄,不足之处请各位大牛不吝斧正。

 

  从backbone的总体结构来看,是一个立即执行的函数表达式,参数是一个匿名函数。(function(){})()和(function(){}())的目的是将函数声明转换为函数表达式,消除Js引擎在识别函数声明和函数表达式上的歧义,除了小括号外还有其他运算符能够做到,详细介绍可以参照这篇文章:js中(function(){…})()立即执行函数写法理解


(function(factory) {
  //模块定义
})(function(root, Backbone, _, $) {
  //Backbone
});

模块处理内容如下:


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。

  首先介绍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类库中,来实现继承父类创造子类。


// 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的解析。


版权声明:本文内容由互联网用户自发贡献,本社区不拥有所有权,也不承担相关法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:yqgroup@service.aliyun.com 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。

用云栖社区APP,舒服~

【云栖快讯】浅析混合云和跨地域网络构建实践,分享高性能负载均衡设计,9月21日阿里云专家和你说说网络那些事儿,足不出户看直播,赶紧预约吧!  详情请点击

网友评论


基于全网公开发布数据、传播路径和受众群体画像,利用语义分析、情感算法和机器学习,分析公众对品牌形象、热点事件和公... 更多>

阿里云推出的一款移动App数据统计分析产品,为开发者提供一站式数据化运营服务 更多>

阿里巴巴自主研发的海量数据实时高并发在线分析云计算服务,使得您可以在毫秒级针对千亿级数据进行即时的多维分析透视和... 更多>

为您提供简单高效、处理能力可弹性伸缩的计算服务,帮助您快速构建更稳定、安全的应用,提升运维效率,降低 IT 成本... 更多>
MaxCompute75折抢购

MaxCompute75折抢购