underscore.js 源码分析(一)
_.each _.map _.refuce _.reduceRight _.find_.each
实例
_.each(list, iteratee, [context])这个方法用于循环遍历, 用于循环 list 对象或者数组, iteratee 是一个遍历函数,接收的参数为遍历之后的结果。 当 list 为数组的时候,传递给 iteratee 函数的参数是 (element, index, list), 当 list 为对象的时候, 传递给 iteratee 函数的参数是 [value, key, list]。对于 context 上下文, 这个决定的是 iteratee 中的 this 的指向值。可选参数, 当 context 忽略的时候 this 指向的是全局变量。_.each 返回值是进行遍历的 list 数组对象。1 | function print(value, index, list) { |
源码分析
在underscore.js 源码中, _.each() 源码为下:1 | _.each = _.forEach = function(obj, iteratee, context) { |
- 分别数组和对象的方法 我平常的时候使用
Object.prootype.toString.call().slice(8, -1)这种方法来分别数组和纯对象,这里使用了一种方法。
1 | if (length === +length) { |
+length 执行的是隐式类型转换,用于将其他的值转换为数字。经过实验,使用 + 进行类型转换的可能性如下: 1 | +null // 0 |
+length 会被转化为 NaN。iteratee = optimizeCb(iteratee, context);optimizaCb函数
optimizaCb 函数用于绑定上下文: 使用 call 以及 apply 的方法实现的改变函数运行的 this 值的改变 接收三个参数: func 运行的函数 context 运行函数需要进行绑定的上下文 argCount 参数的个数 1 | var optimizeCb = function(func, context, argCount) { |
_.each 源码中的使用这个函数的目的是将 iteratee 的上下文 this 绑定到 context 对象。这里有一个 void 0 这里的 void 0 等同于使用 undefined 不同于使用undefined的原因在于: 在javascript中undefined不是一个保留字。代码如下:
1
2
3
4 >var undefined = 1;
>console.log(undefined); // 1 也是可以的
>使用 void 0 作用是这样的
>
_.map
实例
_.map(list, iteratee, [context])通过 使用变换函数 iteratee 将list 中的值映射到一个新的数组。1 | function filter(value) { |
1 | _.map = _.collect = function(obj, iteratee, context) { |
源码分析
- 使用
&&以及||进行计算
这里对于类型转换,使用的时候要注意出现假值的情况使用
&& 以及 || 会首先对于 * 第一个* 操作数进行计算,根据判断结果来决定返回哪一个操作数。 1 | a || b |
a || b 好像备用条件。 如果条件 a 不成立, 执行条件 b, 如果成立,执行条件 a a ? a : b`a && b` 好像通过条件, 如果 `a` 成立,向下执行,如果不成立,打住,返回 `a` 执行的结果 `a ? b : a`
- 使用
Array(length)创建的是一个length长度的数组。
_.reduce
实例
_.reduce(list, iteratee, [memo], context)通过迭代将 list 中的元素归结为一个值。 memo 表示初始参数。1 | function reduceFn(memo, num) { |
源码分析
源码如下:1 | function reduce(obj, iteratee, memo, context) { |
- 在
obj可能是对象或者数组的情况下,当obj是对象的时候,需要产生了一个 使用keys来进行数组操作 - 在迭代的时候, 当没有
memo初始值的时候, 将数组或者对象的第一个值作为memo这里,使用index++来处理的使用 index++ 的时候,相当于 index = index + 1; 但是直接使用的时候还是原来的 index
1
2
3
4
5>let currentIndex = 0;
>let addIndex = currentIndex++; // 相当于先返回 currentIndex 在进行加一操作
>addIndex // 0
>currentIndex // 1
>
- 迭代的过程发生在使用循环赋值的过程中
1
2
3for (; index < length; index++) {
memo = iteratee(memo, obj[currrentIndex], currentIndex, obj);
}
_.reduceRight
实例
_.reduceRight(list, iteratee, [memo], context)类似于使用_.reduce 不过不同于使用 _.reduce 的是,这个是从右边向左进行遍历操作;1 | function contact(a, b) { |
源码分析
1 | _.reduceRight = _.foldr = function(obj, iteratee, memo, context) { |
- 使用
while循环进行判断
1 | while (index-- > 0) { |
_.find
实例
_.find(list, predicate, [context])遍历 list 值 返回第一个通过 predicate 函数返回真值的数值。1 | let list = [1, 2, 3]; |
源码分析
1 | _.find = _.detect = function(obj, predicate, context) { |