美文网首页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