zoukankan      html  css  js  c++  java
  • lodash源码学习(2)

    继续学习lodash,依然是数组的方法

    “Array” Methods

    _.indexOf(array, value, [fromIndex=0])

    获取value在数组 array所在的索引值 使用 SameValueZero方式比较(第一个全等===的元素). 如果 fromIndex 值是负数, 则从array末尾起算

    该方法依赖于strictIndexOf和baseIndexOf方法,先看它们的源码

    //_strictIndexOf.js
    
    /**
     * _.indexOf的专业版本,对元素执行严格的比较方法(===)
     *
     * @param {Array} array 需要处理的数组.
     * @param {*} value 查找的值.
     * @param {number} fromIndex 查找的开始位置.
     * @returns {number} 返回第一个匹配的值的索引,或者-1.
     */
    function strictIndexOf(array, value, fromIndex) {
      var index = fromIndex - 1,//数值索引
          length = array.length;//数组长度
    
      while (++index < length) {//遍历,如果数组中的值和查找的值相同,返回对应的index
        if (array[index] === value) {
          return index;
        }
      }
      return -1;//返回-1
    }
    
    module.exports = strictIndexOf;
    //_baseIndexOf.js
    
    var baseFindIndex = require('./_baseFindIndex'),//baseFindIndex方法(见源码学习(1))
        baseIsNaN = require('./_baseIsNaN'),//判断是不是NaN
        strictIndexOf = require('./_strictIndexOf');//strictIndexOf方法
    
    /**
     * _.indexOf的基本实现,不对fromIndex的范围进行检查
     *
     * @param {Array} array 需要处理的数组.
     * @param {*} value 需要查找的值.
     * @param {number} fromIndex 查找的开始位置.
     * @returns {number} 返回第一个匹配的值的索引,或者-1.
     */
    function baseIndexOf(array, value, fromIndex) {
        //如果value === value(也就是不为NaN),调用strictIndexOf方法,否则调用baseFindIndex方法,判断条件为是否为NaN
        //并且将结果作为返回值返回
      return value === value 
        ? strictIndexOf(array, value, fromIndex)
        : baseFindIndex(array, baseIsNaN, fromIndex);
    }
    
    module.exports = baseIndexOf;

    然后再看indexOf方法的源码

    //indexOf.js
    
    var baseIndexOf = require('./_baseIndexOf'),//baseIndexOf方法
        toInteger = require('./toInteger');//转化为整形
    
    var nativeMax = Math.max;
    
    /**
     *
     *
     * @param {Array} array 需要处理的数组.
     * @param {*} value 需要查找的值.
     * @param {number} [fromIndex=0] 查找的开始位置.
     * @returns {number} 返回第一个匹配的值的索引,或者-1.
     * @example
     *
     * _.indexOf([1, 2, 1, 2], 2);
     * // => 1
     *
     * // Search from the `fromIndex`.
     * _.indexOf([1, 2, 1, 2], 2, 2);
     * // => 3
     */
    function indexOf(array, value, fromIndex) {
      var length = array == null ? 0 : array.length;//数组长度
      if (!length) {//如果为空数组,返回-1
        return -1;
      }
      var index = fromIndex == null ? 0 : toInteger(fromIndex);//查找的起始位置,如果没有传入fromIndex则为0,否则为fromIndex
      if (index < 0) {//如果index为负值,从末尾算起
        index = nativeMax(length + index, 0);
      }
      return baseIndexOf(array, value, index);//调用baseIndexOf方法,并将结果作为返回值返回
    }
    
    module.exports = indexOf;

    _.initial(array)

    得到数组的除了最后一个元素以外的所有元素.

    //initial.js
    
    var baseSlice = require('./_baseSlice');//同Array.slice方法
    
    /**
     * 
     *
     * @param {Array} array 需要处理的数组.
     * @returns {Array} 返回切好的数组.
     * @example
     *
     * _.initial([1, 2, 3]);
     * // => [1, 2]
     */
    function initial(array) {
      var length = array == null ? 0 : array.length;//数组长度
      return length ? baseSlice(array, 0, -1) : [];//如果不为空数组,调用baseSlice方法并将结果返回,否则返回空数组
    }
    
    module.exports = initial;

    _.intersection([arrays])

    取出各数组中都有的元素,使用 SameValueZero方式比较(===).

    _.intersectionBy([arrays], [iteratee=_.identity])

    和_.intersection很像,除了它接受一个遍历器被每个元素调用,生成计算之后的属性当他们比较的时候。遍历器interatee只接收一个参数(value)

    _.intersectionWith([arrays], [comparator])

    和_.intersection很像,除了它接受一个比较规则被每个元素调用,比较方法接受两个参数(arrVal,othVal)

    这三个方法依赖于baseIntersection方法

    //_baseIntersection.js
    
    var SetCache = require('./_SetCache'),//Set缓存数组
        arrayIncludes = require('./_arrayIncludes'),//同Array.includes方法
        arrayIncludesWith = require('./_arrayIncludesWith'),//同Array.includes方法,除了他接受一个比较方法
        arrayMap = require('./_arrayMap'),//同Array.map
        baseUnary = require('./_baseUnary'),//创建一个只有一个参数的方法,忽略其他的参数
        cacheHas = require('./_cacheHas');//判断缓存中是否存在某个元素
    
    var nativeMin = Math.min;
    
    /**
     * _.intersection的基本实现, 不支持遍历器的简写.
     *
     * @private
     * @param {Array} arrays 需要处理的数组.
     * @param {Function} [iteratee] 遍历器,作用于每个元素.
     * @param {Function} [comparator] 比较器,作用于每个元素.
     * @returns {Array} 返回一个数组包含给定所有数组中共有的元素.
     */
    function baseIntersection(arrays, iteratee, comparator) {
      var includes = comparator ? arrayIncludesWith : arrayIncludes,//如果有比较器,为arrayIncludesWith,否则为arrayIncludes
          length = arrays[0].length,//第一个数组的长度
          othLength = arrays.length,//给定的所有数组的长度
          othIndex = othLength,//给定所有数组的索引
          caches = Array(othLength),//创建一个缓存给定数组个数的数组
          maxLength = Infinity,//最大长度
          result = [];//返回结果
      //遍历给定的数组
      while (othIndex--) {
        var array = arrays[othIndex];//当前数组
        if (othIndex && iteratee) {//如果不是第一个数组,并且有遍历器,对当前数组调用遍历器遍历每个元素
          array = arrayMap(array, baseUnary(iteratee));//当前数组为调用之后的数组
        }
        maxLength = nativeMin(array.length, maxLength);//数组的最大长度
        //如果该数组长度超过120就创建Set缓存数组中并添加到caches中(用于优化)
        caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
          ? new SetCache(othIndex && array)
          : undefined;
      }
      array = arrays[0];//给定所有数组中的第一个
    
      var index = -1,//数组索引
          seen = caches[0];//第一个缓存数组,初始为undefined或者new SetCache(0)
    
      outer:
      //遍历第一个数组
      while (++index < length && result.length < maxLength) {
        var value = array[index],//数组元素
            computed = iteratee ? iteratee(value) : value;//如果有遍历器,对改元素调用,得到计算后的值
    
        value = (comparator || value !== 0) ? value : 0;//如果有比较器或者value不为0,value为value,否则为0
        if (!(seen//如果seen有值了,判断是否含有computed,否则判断结果中是否含有computed,如果都没有computed
              ? cacheHas(seen, computed)
              : includes(result, computed, comparator)
            )) {
          othIndex = othLength;//其他数组的索引,初始为给定数组的长度
          //遍历给定的数组,除了第一个
          while (--othIndex) {
            var cache = caches[othIndex];//缓存数组中的值
            //太长的数组就是cache,短的就是arrays[index],判断是否含有computed,如果没有,跳过此次循环
            if (!(cache
                  ? cacheHas(cache, computed)
                  : includes(arrays[othIndex], computed, comparator))
                ) {
              continue outer;
            }
          }
          if (seen) {//如果缓存存在,将computed添加到缓存中
            seen.push(computed);
          }
          result.push(value);//将value添加到结果数组中
        }
      }
      return result;//返回结果数组
    }
    
    module.exports = baseIntersection;

    对应的方法在baseIntersection上进行处理

    //intersection.js
    
    var arrayMap = require('./_arrayMap'),//同Array.map
        baseIntersection = require('./_baseIntersection'),//baseIntersection方法
        baseRest = require('./_baseRest'),//创建可以使用rest参数的方法
        castArrayLikeObject = require('./_castArrayLikeObject');//创建一个类似数组的对象,如果不是为空数组
    
    /**
     * 
     * @param {...Array} [arrays] 需要处理的所有数组.
     * @returns {Array} 返回一个数组包含给定所有数组中共有的元素.
     * @example
     *
     * _.intersection([2, 1], [2, 3]);
     * // => [2]
     */
    var intersection = baseRest(function(arrays) {//创建具备rest参数的方法
      var mapped = arrayMap(arrays, castArrayLikeObject);//将所有数组转化为类似数组的对象
      return (mapped.length && mapped[0] === arrays[0])//如果传入的数组个数不为0,并且第一个参数为数组,调用baseIntersection方法传入mapped,并将结果作为返回值返回,否则返回空数组
        ? baseIntersection(mapped)
        : [];
    });
    
    module.exports = intersection;
    //intersectionBy.js
    
    var arrayMap = require('./_arrayMap'),//同Array.map
        baseIntersection = require('./_baseIntersection'),//baseIntersection方法
        baseIteratee = require('./_baseIteratee'),//遍历器封装
        baseRest = require('./_baseRest'), //创建具有rest参数的方法
        castArrayLikeObject = require('./_castArrayLikeObject'),//创建类似数组的对象
        last = require('./last');//取得数组的最后一个元素
    
    /**
     * 
     * @param {...Array} [arrays] 需要处理的数组.
     * @param {Function} [iteratee=_.identity] 遍历器被每个元素调用.
     * @returns {Array} 返回一个数组包含给定所有数组中共有的元素.
     * @example
     *
     * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor);
     * // => [2.1]
     *
     * // The `_.property` iteratee shorthand.
     * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
     * // => [{ 'x': 1 }]
     */
    var intersectionBy = baseRest(function(arrays) {//创建具备rest参数的方法
      var iteratee = last(arrays),//遍历器为最后一个参数
          mapped = arrayMap(arrays, castArrayLikeObject);//将所有数组转化为类似数组的对象
    
      if (iteratee === last(mapped)) {//如果遍历器和mapped最后一个一样(也就是最后一个参数为数组)
        iteratee = undefined;//不存在遍历器
      } else {
        mapped.pop();//否则将mapped最后一个元素去掉(遍历器转化的元素)
      }
      return (mapped.length && mapped[0] === arrays[0])
      //如果传入的数组个数不为0,并且第一个参数为数组,调用baseIntersection方法传入mapped和iteratee,并且支持属性的简写,并将结果作为返回值返回,否则返回空数组
        ? baseIntersection(mapped, baseIteratee(iteratee, 2))
        : [];
    });
    
    module.exports = intersectionBy;
    //intersectionWith.js
    
    var arrayMap = require('./_arrayMap'),//同Array.map
        baseIntersection = require('./_baseIntersection'),//baseIntersection方法
        baseRest = require('./_baseRest'),//创建具有rest参数的方法
        castArrayLikeObject = require('./_castArrayLikeObject'),//创建类似数组的对象
        last = require('./last');//取得数组的最后一个元素
    
    /**
     *
     * @param {...Array} [arrays] 需要处理的数组.
     * @param {Function} [comparator] 比较方法.
     * @returns {Array} 返回一个数组包含给定所有数组中共有的元素.
     * @example
     *
     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
     * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
     *
     * _.intersectionWith(objects, others, _.isEqual);
     * // => [{ 'x': 1, 'y': 2 }]
     */
    var intersectionWith = baseRest(function(arrays) {//创建具有rest参数的方法
      var comparator = last(arrays),//比较器为最后一个元素
          mapped = arrayMap(arrays, castArrayLikeObject);//将所有数组转化为类似数组的对象
    
      comparator = typeof comparator == 'function' ? comparator : undefined;//比较器如果不为function,则为undefined
      if (comparator) {//如果有比较器,将mapped最后一个元素去掉(比较器转化的元素)
        mapped.pop();
      }
      //如果传入的数组个数不为0,并且第一个参数为数组,调用baseIntersection方法传入mapped和comparator,并将结果作为返回值返回,否则返回空数组
      return (mapped.length && mapped[0] === arrays[0])
        ? baseIntersection(mapped, undefined, comparator)
        : [];
    });
    
    module.exports = intersectionWith;

    _.join(array, [separator=','])

     转化数组为字符串,用指定的分割符将每个元素连接起来.

    //join.js
    
    var arrayProto = Array.prototype;//数组的原型
    
    var nativeJoin = arrayProto.join;//原生join方法
    
    /**
     *
     * @param {Array} array 需要转化的数组.
     * @param {string} [separator=','] 分割符.
     * @returns {string} 返回连接起来的字符串.
     * @example
     *
     * _.join(['a', 'b', 'c'], '~');
     * // => 'a~b~c'
     */
    function join(array, separator) {
      return array == null ? '' : nativeJoin.call(array, separator);//如果数组为空,返回空字符串,否则调用原生的join方法,并将结果返回
    }
    
    module.exports = join;

    _.last(array)

    得到数组的最后一个元素

    //last.js
    
    /**
     *
     * @param {Array} array 需要处理的数组.
     * @returns {*} 返回数组的最后一个元素.
     * @example
     *
     * _.last([1, 2, 3]);
     * // => 3
     */
    function last(array) {
      var length = array == null ? 0 : array.length;
      return length ? array[length - 1] : undefined;//不解释
    }
    
    module.exports = last;

    _.lastIndexOf(array, value, [fromIndex=array.length-1])

    和_.indexOf很像,但是是从右到左开始遍历

    该方法依赖于strictLastIndexOf方法

    //_strictLastIndexOf.js
    
    /**
     * _.lastIndexOf的专业版本,对元素执行严格的比较方法(===).
     *
     * @param {Array} array 需要处理的数组.
     * @param {*} value 需要查找的值.
     * @param {number} fromIndex 查找的开始位置.
     * @returns {number} 返回第一个匹配的元素的索引,或者-1.
     */
    function strictLastIndexOf(array, value, fromIndex) {
      var index = fromIndex + 1;//数值索引
      while (index--) {
        if (array[index] === value) {//遍历,如果数组中的值和查找的值相同,返回对应的index
          return index;
        }
      }
      return index;//返回index(如果没有找到,index的值为-1)
    }
    
    module.exports = strictLastIndexOf;

    再看lastIndexOf方法的源码

    //lastIndexOf.js
    
    var baseFindIndex = require('./_baseFindIndex'),//baseFindIndex方法(见源码学习(1))
        baseIsNaN = require('./_baseIsNaN'),//判断是否为NaN
        strictLastIndexOf = require('./_strictLastIndexOf'),//strictLastIndexOf方法
        toInteger = require('./toInteger');//转化为整型
    
    var nativeMax = Math.max,//原生最大值方法
        nativeMin = Math.min;//原生最小值方法
    
    /**
     *
     * @param {Array} array 需要处理的数组.
     * @param {*} value 需要查找的值.
     * @param {number} [fromIndex=array.length-1] 查找的开始位置.
     * @returns {number} 返回匹配的第一个元素的索引,或者-1.
     * @example
     *
     * _.lastIndexOf([1, 2, 1, 2], 2);
     * // => 3
     *
     * // Search from the `fromIndex`.
     * _.lastIndexOf([1, 2, 1, 2], 2, 2);
     * // => 1
     */
    function lastIndexOf(array, value, fromIndex) {
      var length = array == null ? 0 : array.length;//数组长度
      if (!length) {//如果为空数组,返回-1
        return -1;
      }
      var index = length;//数组索引
      if (fromIndex !== undefined) {//如果有起始位置
        index = toInteger(fromIndex);//转换为整形
        index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);//判断起始位置,在0到length-1之间,如果为负,从末尾算起
      }
      return value === value//如果不是NaN,调用strictLastIndexOf方法,否则调用baseFindIndex方法,并且传入判断条件为baseIsNaN
        ? strictLastIndexOf(array, value, index)
        : baseFindIndex(array, baseIsNaN, index, true);
    }
    
    module.exports = lastIndexOf;

    _.nth(array, [n=0])

    得到数组指定索引的值,如果索引为负值,从数组末尾算起.

    该方法依赖于baseNth方法

    //_baseNth.js
    
    var isIndex = require('./_isIndex');//是否为正确的索引
    
    /**
     * _.nth的基本实现,不强制参数
     *
     * @private
     * @param {Array} array 需要查询的数组
     * @param {number} n 查找元素的index.
     * @returns {*} 返回查找到的元素.
     */
    function baseNth(array, n) {
      var length = array.length;//数组长度
      if (!length) {//如果为空数组,返回空数组
        return;
      }
      n += n < 0 ? length : 0;//n<0从末尾算,否则就是n
      return isIndex(n, length) ? array[n] : undefined;//如果是正确的索引,返回索引对应的值,否则返回undefined
    }
    
    module.exports = baseNth;

    再看nth.js

    //nth.js
    
    var baseNth = require('./_baseNth'),//baseNth方法
        toInteger = require('./toInteger');//转化为整形
    
    /**
     *
     * @param {Array} array 需要查询的数组.
     * @param {number} [n=0] 查找元素的index..
     * @returns {*} 返回查找到的元素.
     * @example
     *
     * var array = ['a', 'b', 'c', 'd'];
     *
     * _.nth(array, 1);
     * // => 'b'
     *
     * _.nth(array, -2);
     * // => 'c';
     */
    function nth(array, n) {
      return (array && array.length) ? baseNth(array, toInteger(n)) : undefined;//不解释
    }
    
    module.exports = nth;

    _.pull(array, [values])

    移除数组array中所有和 values 相等的元素,使用 SameValueZero 进行全等比较.

    _.pullAll(array, values)

    和_.pull很像除了它接受一个需要移除的元素的数组

    _.pullAllBy(array, values, [iteratee=_.identity])

    这个方法和_.pullAll很像除了它接受一个遍历方法被每个元素调用,遍历方法接受一个参数(value)

    _.pullAllWith(array, values, [comparator])

    这4个方法都依赖于basePullAll方法

    //_basePullAll.js
    
    var arrayMap = require('./_arrayMap'),//同Array.map
        baseIndexOf = require('./_baseIndexOf'),//同Array.indexOf,上面已分析
        baseIndexOfWith = require('./_baseIndexOfWith'),//类似baseIndexOf,除了接受一个比较方法
        baseUnary = require('./_baseUnary'),//创建一个只有一个参数的方法,忽略其他的参数
        copyArray = require('./_copyArray');//拷贝数组
    
    var arrayProto = Array.prototype;//数组原形
    
    var splice = arrayProto.splice;//原生splice方法
    
    /**
     * _.pullAllBy的基本实现,不支持遍历器的简写
     *
     * @private
     * @param {Array} array 需要修改的数组.
     * @param {Array} values 需要移除的元素.
     * @param {Function} [iteratee] 遍历器,对每个元素调用.
     * @param {Function} [comparator] 比较器,对每个元素调用.
     * @returns {Array} 返回修改之后的数组.
     */
    function basePullAll(array, values, iteratee, comparator) {
      var indexOf = comparator ? baseIndexOfWith : baseIndexOf,//选择indexOf方法,如果传入比较器为baseIndexOfWith,否则为baseIndexOf
          index = -1,//数值索引
          length = values.length,//数组长度
          seen = array;//获取一个array的引用
    
      if (array === values) {//如果需要移除的元素和需要修改的数组一样,拷贝一份values
        values = copyArray(values);
      }
      if (iteratee) {//如过存在遍历器,对数组进行遍历操作
        seen = arrayMap(array, baseUnary(iteratee));
      }
      //遍历需要移除的数组
      while (++index < length) {
        var fromIndex = 0,//元素在数组中的开始位置
            value = values[index],//需要移除的元素
            computed = iteratee ? iteratee(value) : value;//如果有遍历器对value进行调用,得到 计算后的value(也就是computed)
        //循环执行indexOf方法,如果seen中,直到找不到computed为止
        while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
          if (seen !== array) {//seen和array不相等即存在遍历器,对seen执行splice方法移除fromIndex的元素
            splice.call(seen, fromIndex, 1);
          }
          //对array执行splice方法移除fromIndex的元素
          splice.call(array, fromIndex, 1);
        }
      }
      return array;//返回修改后的array
    }
    
    module.exports = basePullAll;

    相对应的方法的源码

    //pullAll.js
    
    var basePullAll = require('./_basePullAll');//basePullAll方法
    
    /**
     *
     * @param {Array} array 需要修改的数组.
     * @param {Array} values 需要移除的值.
     * @returns {Array} 返回修改后的数组.
     * @example
     *
     * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
     *
     * _.pullAll(array, ['a', 'c']);
     * console.log(array);
     * // => ['b', 'b']
     */
    function pullAll(array, values) {
      return (array && array.length && values && values.length)
        ? basePullAll(array, values)
        : array;//不解释
    }
    
    module.exports = pullAll;
    //pull.js
    
    var baseRest = require('./_baseRest'),//创建具有rest参数的方法
        pullAll = require('./pullAll');
    
    /**
     *
     * @param {Array} array 需要修改的数组.
     * @param {...*} [values] The values to remove.
     * @returns {Array} Returns `array`.
     * @example
     *
     * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
     *
     * _.pull(array, 'a', 'c');
     * console.log(array);
     * // => ['b', 'b']
     */
    var pull = baseRest(pullAll);//将pullAll转换成可以使用rest参数的方法(pull(array,...values))
    
    module.exports = pull;
    //pullAllBy.js
    
    var baseIteratee = require('./_baseIteratee'),//封装遍历器
        basePullAll = require('./_basePullAll');//basePullAll方法
    
    /**
     *
     * @param {Array} array 需要修改的数组.
     * @param {Array} values 需要移除的值.
     * @param {Function} [iteratee=_.identity] 遍历器,被每个元素调用.
     * @returns {Array} 返回修改后的数组.
     * @example
     *
     * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }];
     *
     * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x');
     * console.log(array);
     * // => [{ 'x': 2 }]
     */
    function pullAllBy(array, values, iteratee) {
      return (array && array.length && values && values.length)
        ? basePullAll(array, values, baseIteratee(iteratee, 2))
        : array;//不解释
    }
    
    module.exports = pullAllBy;
    //pullWidth.js
    
    var basePullAll = require('./_basePullAll');//basePullAll方法
    
    /**
     *
     * @param {Array} array 需要修改的数组.
     * @param {Array} values 需要移除的元素.
     * @param {Function} [comparator] 比较器被每个元素调用.
     * @returns {Array} 返回修改后的数组.
     * @example
     *
     * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }];
     *
     * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual);
     * console.log(array);
     * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
     */
    function pullAllWith(array, values, comparator) {
      return (array && array.length && values && values.length)
        ? basePullAll(array, values, undefined, comparator)
        : array;//不解释
    }
    
    module.exports = pullAllWith;

    一天一点进步,一步一个脚印~~~

  • 相关阅读:
    Apktool 和 Jeb 给出的不同的smali语法
    System.exit(0);和finish();,push原理
    Mac的环境变量
    Android Jni(Java Native Interface)笔记
    记录用到的一些linux命令和疑难解决
    记录一些好用的软件的名字
    数据分析准备过程
    独热编码 pandas get_dummies
    学习英语的方法
    精确率与回召率与 F1-Meature
  • 原文地址:https://www.cnblogs.com/wandiao/p/7118223.html
Copyright © 2011-2022 走看看