一直想针对一个框架的源码好好的学习一下编程思想和技巧,提高一下自己的水平,但是看过一些框架的源码,都感觉看的莫名其妙,看不太懂,最后找到这个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源码解析(一)的更多相关文章

  1. underscore.js源码解析(五)—— 完结篇

    最近公司各种上线,所以回家略感疲惫就懒得写了,这次我准备把剩下的所有方法全部分析完,可能篇幅过长...那么废话不多说让我们进入正题. 没看过前几篇的可以猛戳这里: underscore.js源码解析( ...

  2. underscore.js源码解析(四)

    没看过前几篇的可以猛戳这里: underscore.js源码解析(一) underscore.js源码解析(二) underscore.js源码解析(三) underscore.js源码GitHub地 ...

  3. underscore.js源码解析(三)

    最近工作比较忙,做不到每周两篇了,周末赶着写吧,上篇我针对一些方法进行了分析,今天继续. 没看过前两篇的可以猛戳这里: underscore.js源码解析(一) underscore.js源码解析(二 ...

  4. underscore.js源码解析(二)

    前几天我对underscore.js的整体结构做了分析,今天我将针对underscore封装的方法进行具体的分析,代码的一些解释都写在了注释里,那么废话不多说进入今天的正文. 没看过上一篇的可以猛戳这 ...

  5. underscore.js源码解析【'_'对象定义及内部函数】

    (function() { // Baseline setup // -------------- // Establish the root object, `window` (`self`) in ...

  6. underscore.js源码解析【对象】

    // Object Functions // ---------------- // Keys in IE < 9 that won't be iterated by `for key in . ...

  7. underscore.js源码解析【函数】

    // Function (ahem) Functions // ------------------ // Determines whether to execute a function as a ...

  8. underscore.js源码解析【数组】

    // Array Functions // --------------- // Get the first element of an array. Passing **n** will retur ...

  9. underscore.js源码解析【集合】

    // Collection Functions // -------------------- // The cornerstone, an `each` implementation, aka `f ...

随机推荐

  1. 启动android monitor报错解决办法

    再这汇总一下这段时间使用android monitor新遇到的问题,特汇总对应问题解决办法如下: 1.确保JDK和Android studio位数相同,比如JDK使用的是64位,studio也要是64 ...

  2. js实现千位分隔符——str.replace()用法

    /*js*/function commafy(num){ return num && num.toString().replace(/(\d{1,3})(?=(\d{3})+(?:$| ...

  3. Tengine 2.1.2 (nginx/1.6.2)安装配置,淘宝 Web 服务器

    简介 Tengine是由淘宝网发起的Web服务器项目.它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性.Tengine的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了很 ...

  4. 【转】ajax 跨域 headers JavaScript ajax 跨域请求 +设置headers 实践

    解决跨域调用服务并设置headers 主要的解决方法需要通过服务器端设置响应头.正确响应options请求,正确设置 JavaScript端需要设置的headers信息 方能实现. 此处手札 供后人参 ...

  5. css 文本溢出

    多行文本溢出处理: display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; // 3 行 overflow ...

  6. MetaMask/metamask-extension-provider

    用来探测你的浏览器中有没有安装metamask插件 https://github.com/MetaMask/metamask-extension-provider MetaMask Extension ...

  7. RedHat 7.3 Oracle 12.2.0.1 RAC 安装手册(转)

    1  准备工作 1.1   关于GRID的一些变化 1.1.1  简化的基于映像的Oracle Grid Infrastructure安装 从Oracle Grid Infrastructure 12 ...

  8. 8.UDP协议

    传输层协议:TCP UDP TCP和UDP有什么区别? TCP是面向连接的 UDP是面向无连接.在互通之前,面向连接的协议会先建立连接,如TCP会三次握手.所谓的建立连接,是为了在客户端和服务端维护连 ...

  9. 动态代理实现设置tomcat请求编码

    1)htmlcode: <html> <head> <title>$Title$</title> </head> <body> ...

  10. Java中 Vector的使用详解

    Vector 可实现自动增长的对象数组. java.util.vector提供了向量类(Vector)以实现类似动态数组的功能. 创建了一个向量类的对象后,可以往其中随意插入不同类的对象,即不需顾及类 ...