你的位置:首页 > Java教程

[Java教程]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中的方法进行具体解析,感谢大家的观看,也希望能够和大家互相交流学习,有什么分析的不对的地方欢迎大家批评指出

参考资料

https://segmentfault.com/a/1190000000515420http://yalishizhude.github.io/2015/09/22/underscore-source/