Underscore.js 1.8.3
http://underscorejs.org
(c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
写在最前
第一次尝试读js源码,以比较简短易读的underscore为开端。水平浅薄,参考了一些大神的解读以加深理解,均以引用形式标出~
源码解读
整体结构
|
|
整个函数通过一个立即执行函数实现,起到隔离作用域的目的,这样一方面避免其他代码对该函数内部造成影响,另一方面可以防止全局变量污染全局空间。
BASELINE SETUP部分
原型赋值[1]
|
|
此种赋值方式,使代码便于压缩。原因是原先的代码中假如需要扩展属性,需通过Object.prototype.xxx = ...
的方式,则必须保留Object
、prototype
以供浏览器识别,导致无法压缩。
其中Symbol
是ES6中规定的第七种基本类型,用来作为对象属性的标识符。
内部回调函数
Underscore中运用到了大量的回调,因此对其都进行了特殊处理。
首先通过一个optimizeCb函数对传入的函数进行参数判断,用于在重复使用中改变执行函数的作用域,保证上下文的正确性。
argCount
为1:只需要传递当前值value
,sortedIndex
、times
函数;argCount
为2:已被省略;argCount
为3:加入当前索引index
和集合collection
;argCount
为4:又加入累计值accumulator
;
另外又通过cb函数对集合元素进行回调处理。
builtinIterate
为内置迭代,若用户修改了迭代器_.iteratee
,则采用新的迭代器;- 若传入
null
,则返回自身; - 若传入函数,则返回该函数的回调处理函数;
- 若传入对象,则返回是否匹配属性值;
- 若是其他情况,则返回相应的属性访问器(value是数组?);
指定函数
createAssigner是underscore中一个重要的内部方法。在三处被调用,分别是
这三个函数用于扩展对象,将对象上的属性拷贝到另一个对象上。_.extend
和_.extendOwn
的区别在于分别使用_.allKeys
和_keys
,即前者拷贝所有属性,后者只拷贝自身属性,在下方createAssigner
代码块中的第8行中生效。_.defaults
在此基础上加入参数true
,因此在第12行中,只有属性值为undefined
时才会进行拷贝,即当出现相同的key
时,只取最早出现的属性值。
Tip: Underscore中采用
void 0
代替undefined
,避免undefined
被重写。
剩余参数
Underscore通过restArgs
函数,模拟了ES6的剩余参数。首先由startIndex
来指定剩余参数的开始位置,若未指定则默认为最后一个参数。之后从指定好的位置开始遍历参数对象,放入rest
数组中。最后执行函数调用。
COLLECTION FUNCTIONS部分
FUNCTION FUNCTIONS部分
函数节流
如果将水龙头拧紧直到水是以水滴的形式流出,那每隔一段时间,就会有一滴水流出。即预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期。
主要适用场景有鼠标移动mousemove事件和DOM元素动态定位,如window对象的resize/scroll事件。
函数去抖
如果用手指一直按住一个弹簧,它将不会弹起直到你松手为止。即空闲时间必须大于或等于一定值的时候,才会执行调用方法。
主要适用场景是文本输入keydown/keyup事件,例如做autocomplete。
Object Functions部分
createAssigner
|
|
这是一个经典的闭包实现,有三个方法用到了这个内部函数——
_.extend = createAssigner(_.allKeys);
_.extendOwn = _.assign = createAssigner(_.keys);
_.defaults = createAssigner(_.allKeys, true);
这个函数本身很简单,想提及的一方面是除了extend和extendOwn,还专门设置了defaults函数通过一个defaults属性来防止覆盖原有项;另一方面,从代码中就不难发现,这里实现的是一个浅拷贝。因此在使用时我会在扩充一个深拷贝。
深拷贝相比于浅拷贝,它不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上。这就不会存在浅拷贝修改属性后指向同一个对象的问题。
来一个简单的深拷贝实现。
参考
- 知乎专栏 — Underscore源码分析系列
- 亚里士朱德的博客 — js高手进阶之路:underscore源码经典
- GitHub — underscore-1.8.3.js 源码解读