underscore.js源码解析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了underscore.js源码解析相关的知识,希望对你有一定的参考价值。

一直想针对一个框架的源码好好的学习一下编程思想和技巧,提高一下自己的水平,但是看过一些框架的源码,都感觉看的莫名其妙,看不太懂,最后找到这个underscore.js由于这个比较简短,一千多行,而且读起来容易一些,所以就决定是它了,那废话不多说开始我们的源码学习。

underscore.js源码GitHub地址: https://github.com/jashkenas/underscore/blob/master/underscore.js
 
本文解析的underscore.js版本是1.8.3
 

结构解析

 
我们先从整体的结构开始分析(其中加入了注释加以解释说明)
 
  1 (function() {
  2   // 创建一个root对象,在浏览器中表示为window(self)对象,在Node.js中表示global对象,
  3   // 之所以用用self代替window是为了支持Web Worker
  4   var root = typeof self == ‘object‘ && self.self === self && self ||
  5             typeof global == ‘object‘ && global.global === global && global ||
  6             this;
  7   // 保存"_"(下划线变量)被覆盖之前的值
  8   var previousUnderscore = root._;
  9   // 原型赋值,便于压缩
 10   var ArrayProto = Array.prototype, ObjProto = Object.prototype;
 11   // 将内置对象原型中的常用方法赋值给引用变量,以便更方便的引用
 12   var push = ArrayProto.push,
 13       slice = ArrayProto.slice,
 14       toString = ObjProto.toString,
 15       hasOwnProperty = ObjProto.hasOwnProperty;
 16   // 定义了一些ECMAScript 5方法
 17   var nativeIsArray = Array.isArray,
 18       nativeKeys = Object.keys,
 19       nativeCreate = Object.create;
 20   //跟神马裸函数有关,我也不清楚什么意思,有知道可以告诉我
 21   var Ctor = function(){};
 22   // 创建一个下划线对象
 23   var _ = function(obj) {
 24     // 如果在"_"的原型链上(即_的prototype所指向的对象是否跟obj是同一个对象,要满足"==="的关系)
 25     if (obj instanceof _) return obj;
 26     // 如果不是,则构造一个
 27     if (!(this instanceof _)) return new _(obj);
 28     // 将underscore对象存放在_.wrapped属性中
 29     this._wrapped = obj;
 30   };
 31   // 针对不同的宿主环境, 将Undersocre的命名变量存放到不同的对象中
 32   if (typeof exports != ‘undefined‘ && !exports.nodeType) {//Node.js
 33     if (typeof module != ‘undefined‘ && !module.nodeType && module.exports) {
 34       exports = module.exports = _;
 35     }
 36     exports._ = _;
 37   } else {//浏览器
 38     root._ = _;
 39   }
 40   //版本号
 41   _.VERSION = ‘1.8.3‘;
 42   //下面是各种方法以后的文章中会具体说明
 43   .
 44   .
 45   .
 46   .
 47   .
 48   .
 49   // 创建一个chain函数,用来支持链式调用
 50   _.chain = function(obj) {
 51     var instance = _(obj);
 52     //是否使用链式操作
 53     instance._chain = true;
 54     return instance;
 55   };
 56   // 返回_.chain里是否调用的结果, 如果为true, 则返回一个被包装的Underscore对象, 否则返回对象本身
 57   var chainResult = function(instance, obj) {
 58     return instance._chain ? _(obj).chain() : obj;
 59   };
 60   // 用于扩展underscore自身的接口函数
 61   _.mixin = function(obj) {
 62     //通过循环遍历对象来浅拷贝对象属性
 63     _.each(_.functions(obj), function(name) {
 64       var func = _[name] = obj[name];
 65       _.prototype[name] = function() {
 66         var args = [this._wrapped];
 67         push.apply(args, arguments);
 68         return chainResult(this, func.apply(_, args));
 69       };
 70     });
 71   };
 72   _.mixin(_);
 73   // 将Array.prototype中的相关方法添加到Underscore对象中, 这样Underscore对象也可以直接调用Array.prototype中的方法
 74   _.each([‘pop‘, ‘push‘, ‘reverse‘, ‘shift‘, ‘sort‘, ‘splice‘, ‘unshift‘], function(name) {
 75     //方法引用
 76     var method = ArrayProto[name];
 77     _.prototype[name] = function() {
 78       // 赋给obj引用变量方便调用
 79       var obj = this._wrapped;
 80       // 调用Array对应的方法
 81       method.apply(obj, arguments);
 82       if ((name === ‘shift‘ || name === ‘splice‘) && obj.length === 0) delete obj[0];
 83       //支持链式操作
 84       return chainResult(this, obj);
 85     };
 86   });
 87 
 88   // 同上,并且支持链式操作
 89   _.each([‘concat‘, ‘join‘, ‘slice‘], function(name) {
 90     var method = ArrayProto[name];
 91     _.prototype[name] = function() {
 92       //返回Array对象或者封装后的Array
 93       return chainResult(this, method.apply(this._wrapped, arguments));
 94     };
 95   });
 96   //返回存放在_wrapped属性中的underscore对象
 97   _.prototype.value = function() {
 98     return this._wrapped;
 99   };
100 
101   // 提供一些方法方便其他情况使用
102   _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
103   _.prototype.toString = function() {
104     return ‘‘ + this._wrapped;
105   };
106 
107   // 对AMD支持的一些处理
108   if (typeof define == ‘function‘ && define.amd) {
109     define(‘underscore‘, [], function() {
110       return _;
111     });
112   }
113 }());

总结

具体分析在上面源码中的注释里写的已经很详细了,下面再从头理顺一下整体的结构:
 
首先underscore包裹在一个匿名自执行的函数当中
内部定义了一个"_"变量
将underscore中的相关方法添加到_原型中,创建的_对象就具备了underscore方法
将Array.prototype中的相关方法添加到Underscore对象中, 这样Underscore对象也可以直接调用Array.prototype中的方法

之后的文章中,我会针对underscore中的方法进行具体解析,感谢大家的观看,也希望能够和大家互相交流学习,有什么分析的不对的地方欢迎大家批评指出

 

以上是关于underscore.js源码解析的主要内容,如果未能解决你的问题,请参考以下文章

underscore.js源码解析函数

underscore.js源码解析数组

underscore.js源码解析对象

underscore.js源码解析集合部分

underscore.js源码研究

underscore.js 预编译模板使用