美文网首页js css html
2022-04-20/21 lodash源码学习 - initi

2022-04-20/21 lodash源码学习 - initi

作者: 网恋被骗二块二 | 来源:发表于2022-04-21 11:10 被阅读0次

function initial(array)
获取数组中除了最后一个元素之外的所有元素
(ps:前面看了这么多代码,不用看都猜到是参数合法后,调用baseSlice了)

@param {Array} array The array to query.
要查询的数组

function initial(array) {
        //  拿取数组长度
        var length = array == null ? 0 : array.length;
        //  数组长度存在则调用截取方法,否则返回空数组
        return length ? baseSlice(array, 0, -1) : [];
      }

function join(array, separator)
将数组中的所有元素转换为由 separator 分隔的字符串。

@param {Array} array The array to convert.
需要转换的数组

@param {string} [separator=','] The element separator.
分隔符

function join(array, separator) {
        //   数组参数没有传递的话,返回空字符串
        // 否则调用nativeJoin,并用call改变函数指向
        return array == null ? '' : nativeJoin.call(array, separator);
      }

(但实际上,lodash的开发还是偷了些懒,这个nativeJoin源自arrayProto中的join,而arrayProto则被赋值为Array.prototype,所以join方法直接用的JavaScript原生的。不过用纯JS实现的话,其实也比较简单,遍历数组,并根据分隔符是否传递而决定输出内容[拼接字符串])


function last(array)
获取数组中的最后一个元素

@param {Array} array The array to query.
要检索的数组

function last(array) {
        //   获取数组长度
        var length = array == null ? 0 : array.length;
        // 长度存在 = 数组有内容  》》》 返回最后一个参数
        // 不存在说明数组本身为空或者其他,返回undefined
        return length ? array[length - 1] : undefined;
      }

function lastIndexOf(array, value, fromIndex)
这个方法类似 _.indexOf,除了它是从右到左遍历元素的

@param {Array} array The array to inspect.
需要检索的数组

@param {*} value The value to search for.
要检索的值

@param {number} [fromIndex=array.length-1] The index to search from.
检索 index 的起点

function lastIndexOf(array, value, fromIndex) {
        //   老规矩,先来判定数组的长度,也就是数组是否是对于该函数合法的数组
        var length = array == null ? 0 : array.length;
        if (!length) {
            // 若数组为空或其他,返回-1
          return -1;
        }
        // lastIndexOf 是从右到左遍历,所以index[第三个参数]默认情况下为数组的长度
        var index = length;
        // 现在来判断第三个参数是否传递,若为传递,该参数为undefined
        if (fromIndex !== undefined) {
            // 此条件下,该参数有内容,使用toInteger将参数转化为有效的数字
          index = toInteger(fromIndex);
        //   如果转化后该参数小于零,那么为其增加数组长度的数值,最小不低于0
        //   如果转化后该参数大于零,那么和数组最大索引比较,最大不超过数组索引
          index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);
        }
        // value === value 这一步确实不明白用意为何?
        // 默认是直接调用strictLastIndexOf,和indexOf调用的strictIndexOf有区别
        // 注意index是先设置默认值,在判断是否传参,因为先处理的话,toInteger也能够将undefined转化为对应的数字
        return value === value
          ? strictLastIndexOf(array, value, index)
          : baseFindIndex(array, baseIsNaN, index, true);
      }

lastIndexOf

function strictLastIndexOf(array, value, fromIndex) {
        // 注意在lastIndexOf中,传递过来的fromIndex参数是该数组的最大索引,而不是数组的长度
        // 这里把fromIndex+1和获取array.length作用是相同的,不必纠结
      var index = fromIndex + 1;
    //   遍历,从右到左,所以是index--
      while (index--) {
        //  判断要查询的值,需要用全等于,如果是 ==,那么会发生隐式数据类型转换,
        if (array[index] === value) {
            // 返回索引值
          return index;
        }
      }
    //   如果一直遍历到没有结果,那么当时条件不成立时,index的值是0
    //   而在此处,return时又调用了一次index,那么会执行 index-1 的操作,所以可以返回 -1
      return index;
    }

function reverse(array)
反转数组,第一个元素移动到最后一位,第二个元素移动到倒数第二,类似这样。

@param {Array} array The array to modify.

function reverse(array) {
        //   数组存在且调用reverse,不存在返回该值本身
        return array == null ? array : nativeReverse.call(array);
      }

(该方法也是直接使用的JavaScript原型方法,要写原生JS的话也能够实现最基本的,因为reverse是会改变原数组的顺序,所以大致代码如下:)

var reverseNew = function (array) {
            // 拷贝数组内容
            const arrayCopy = [...array]
            // 取出长度
            let length = array.length
            // 重新赋值的洗标
            let index = 0
            // 循环copy数组
            while (length) {
                // 对原数组内容重新赋值,index++和--length可以保证在下一次循环时能够获取到对应下标的内容,并且循环正常进行
                array[index++] = arrayCopy[--length]
            }
        }

本来打算看pull的,但是pull在lodash里的调用好像有点复杂,不过pull最终是指向pullAll这个方法,所以先了解pullAll—————

function pullAll(array, values)
这个方式类似 _.pull,除了它接受数组形式的一系列值。

@param {Array} array The array to modify.
需要调整的数组

@param {Array} values The values to remove.
要移除的值[数组形式]

(ps:看代码前的个人猜想,因为第二个参数是数组形式,basePullAll会不会调用lodash内部的baseIndexOf?)

function pullAll(array, values) {
        //  新的判断方式,数组存在 且 长度不为0或undefined 且 第二个参数存在 且 第二个参数长度不为0或undefined
        return (array && array.length && values && values.length)
        // 以上条件都满足,调用basePullAll并传入参数
          ? basePullAll(array, values)
        //   否则返回原数组
          : array;
      }

function basePullAll(array, values, iteratee, comparator)
pullAllBy的基本实现,不支持iteratee缩写。(只能机翻哈,英语水平不是太好)

@param {Array} array The array to modify.
要修改的数组

@param {Array} values The values to remove.
要删除的值[type 数组]

@param {Function} [iteratee] The iteratee invoked per element.
每个元素调用的iteratee[iteratee应该是迭代函数]

@param {Function} [comparator] The comparator invoked per element.
每个元素调用的比较器

(后面basePullAll调用到的相关方法也写在下面了)

function basePullAll(array, values, iteratee, comparator) {
        //   第四个参数是否存在,存在则使用baseIndexOfWith方法,不存在则使用baseIndexOf
        var indexOf = comparator ? baseIndexOfWith : baseIndexOf,
        // 数组循环的初始下标
            index = -1,
            // 删除数组的长度
            length = values.length,
            // 拷贝一份数组(地址?)
            seen = array;
  
        if (array === values) {
            // 如果原数组和删除数数组都存在,那么重新拷贝一份删除数组?
          values = copyArray(values);
        }
        if (iteratee) {
            // 如果第三个参数存在(函数参数),则表示要对原数组中的每一项内容做修改
            // 调用 _.map 的基础版本,将其修改内容后的数组重新赋值给 seen
          seen = arrayMap(array, baseUnary(iteratee));
        }
        // 循环(比对删除数组的长度)
        while (++index < length) {
            // indexOf查询到该值的下标,默认为0
          var fromIndex = 0,
            // 拿到当前需要被删除的变量
              value = values[index],
            // 需要被查找的变量,如果iteratee存在,那么将处理该值(之前处理的是原数组,这次处理的是删除数组)
              computed = iteratee ? iteratee(value) : value;
            // 如果调用indexOf能够在seen里找到对应元素的下标
            // indexOf调用,传递参数,seen[处理后的数组]、computed[需要查询的项]、fromIndex[查询时的起始下标]、comparator[比较器]
            // 如果数组中有多个该项存在,那么循环会一直成立,直到找不到该值为止
          while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
            // 如果处理后的数组和原数组不同(如,原数组中混杂有字符串和数字,而处理后的数组是将其都转化成数字,那么这样是不同的)
            if (seen !== array) {
                // 那么处理后的数组也要删除对应的该项
                // 此项成立的条件在于,iteratee参数是否传递,而indexOf查询的基础是在seen上
                // 如果iteratee没有传递,那么在方法开头,seen=array,此时删除array本身的内容,seen也会跟随变动
                // 而iteratee传递之后,两个数组必然不相等,那么seen也要同步array被删除的项,否则该循环会一直存在,直到array数组内容全部被清空
              splice.call(seen, fromIndex, 1);
            }
            // 删除array中的元素,本身就是对array数组的修改,所以此步骤必须进行
            splice.call(array, fromIndex, 1);
          }
        }
        return array;
      }

function copyArray(source, array)

@param {Array} source The array to copy values from.
要从中复制值的数组

@param {Array} [array=[]] The array to copy values to.
要将值复制到的数组

function copyArray(source, array) {
        //   循环的起始下标
        var index = -1,
        // 资源数组的数组长度
            length = source.length;
        // 若第一个参数存在,则保留原本,若不存在,则创建一个资源数组相同长度空数组
        array || (array = Array(length));
        // 遍历
        while (++index < length) {
            // 资源数组的当前内容赋值给拷贝数组
          array[index] = source[index];
        }
        // 返回拷贝好的数组
        return array;
      }

function baseUnary(func)
unary创建一个最多接受一个参数的函数,忽略多余的参数。baseUnary_.unary 的基本实现,不支持存储元数据。

function baseUnary(func) {
        // 闭包返回一个新函数,这个函数可以接收一个参数
      return function(value) {
        //   这个闭包返回的函数再调用最外层baseUnary接收的函数参数,该函数参数拿到第一次闭包时传入的参数
        return func(value);
      };
    }

比如

_.map(['6', '8', '10'], _.unary(parseInt));
// => [6, 8, 10]

function arrayMap(array, iteratee)
不支持迭代简写的数组的 _.map 专用版本。
众所周知,数组中的 map 方法是用于修改数组中参数内容的,也叫做映射

function arrayMap(array, iteratee) {
        // 循环初始下标
      var index = -1,
        //  数组长度拿取
          length = array == null ? 0 : array.length,
        //  创建一个固定长度的新数组
          result = Array(length);
        //  遍历数组,若数组为空或非数组,该循环不成立,返回所有值为undefined的新数组
      while (++index < length) {
        // 新数组当前下标赋值
        // 结合basePullAll中调用arrayMap时传入的baseUnary方法,此时iteratee是basePullAll中的一个参数,而该参数必须是一个函数
        // 具体该函数应该是什么?并且返回什么?要看传入的方法是什么
        result[index] = iteratee(array[index], index, array);
      }
      return result;
    }

相关文章

网友评论

    本文标题:2022-04-20/21 lodash源码学习 - initi

    本文链接:https://www.haomeiwen.com/subject/ianmertx.html