lodash源码学习(4)

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

“Array” Methods

_.take(array, [n=1])

 创建一个数组片段包含从数组开始获取的n个元素.

//take.js

var baseSlice = require('./_baseSlice'),//同Array.slice(见源码学习(3))
    toInteger = require('./toInteger');//转化为整型

/**
 *
 * @param {Array} array 需要查询的数组.
 * @param {number} [n=1] 需要获取的数量.
 * @param- {Object} [guard] 能够作为遍历器被像_.map这样的方法调用.
 * @returns {Array} 返回切好的数组.
 * @example
 *
 * _.take([1, 2, 3]);
 * // => [1]
 *
 * _.take([1, 2, 3], 2);
 * // => [1, 2]
 *
 * _.take([1, 2, 3], 5);
 * // => [1, 2, 3]
 *
 * _.take([1, 2, 3], 0);
 * // => []
 */
function take(array, n, guard) {
  if (!(array && array.length)) {//如果没有array,或者为空数组,返回空数组
    return [];
  }
  n = (guard || n === undefined) ? 1 : toInteger(n);//n默认为1
  return baseSlice(array, 0, n < 0 ? 0 : n);//调用baseSlice方法并将结果作为返回值返回
}

module.exports = take;

_.takeRight(array, [n=1])

创建一个数组片段包含从数组末尾获取的n个元素..

//takeRight.js

var baseSlice = require('./_baseSlice'),//同Array.slice
    toInteger = require('./toInteger');//转化为整型

/**
 *
 * @param {Array} array 需要查询的数组.
 * @param {number} [n=1] 需要获取的元素数量.
 * @param- {Object} [guard] 能够作为遍历器被像_.map这样的方法调用.
 * @returns {Array} 返回切好的数组片段.
 * @example
 *
 * _.takeRight([1, 2, 3]);
 * // => [3]
 *
 * _.takeRight([1, 2, 3], 2);
 * // => [2, 3]
 *
 * _.takeRight([1, 2, 3], 5);
 * // => [1, 2, 3]
 *
 * _.takeRight([1, 2, 3], 0);
 * // => []
 */
function takeRight(array, n, guard) {
  var length = array == null ? 0 : array.length;
  if (!length) {//如果没有array,或者为空数组,返回空数组
    return [];
  }
  n = (guard || n === undefined) ? 1 : toInteger(n);//n默认为1
  n = length - n;//从末尾开始算
  return baseSlice(array, n < 0 ? 0 : n, length);//调用baseSlice方法并将结果作为返回值返回
}

module.exports = takeRight;

_.takeRightWhile(array, [predicate=_.identity])

 创建一个数组,包含从数组的末尾开始获取元素,直到判断结果为false为止的元素.判断条件接收三个参数(value, index, array)

//takeRightWhile.js

var baseIteratee = require('./_baseIteratee'),//遍历器封装
    baseWhile = require('./_baseWhile');//从第一个不满足predicate 条件的元素开始截取数组(见源码学习(1))

/**
 *
 * @param {Array} array 需要查询的数组.
 * @param {Function} [predicate=_.identity] 判断条件.
 * @returns {Array} 返回切好的数组片段.
 * @example
 *
 * var users = [
 *   { 'user': 'barney',  'active': true },
 *   { 'user': 'fred',    'active': false },
 *   { 'user': 'pebbles', 'active': false }
 * ];
 *
 * _.takeRightWhile(users, function(o) { return !o.active; });
 * // => objects for ['fred', 'pebbles']
 *
 * // The `_.matches` iteratee shorthand.
 * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false });
 * // => objects for ['pebbles']
 *
 * // The `_.matchesProperty` iteratee shorthand.
 * _.takeRightWhile(users, ['active', false]);
 * // => objects for ['fred', 'pebbles']
 *
 * // The `_.property` iteratee shorthand.
 * _.takeRightWhile(users, 'active');
 * // => []
 */
function takeRightWhile(array, predicate) {//如果没有array或者为空数组,返回空数组,否则调用baseWhile方法,并将判断条件封装,使之支持简写,传入第四个参数为true,从右边开始。
  return (array && array.length)
    ? baseWhile(array, baseIteratee(predicate, 3), false, true)
    : [];
}

module.exports = takeRightWhile;

_.takeWhile(array, [predicate=_.identity])

创建一个数组,包含从数组的开始开始获取元素,直到判断结果为false为止的元素.判断条件接收三个参数(value, index, array)

//takeWhile.js

var baseIteratee = require('./_baseIteratee'),//遍历器封装
    baseWhile = require('./_baseWhile');//从第一个不满足predicate 条件的元素开始截取数组(见源码学习(1))

/**
 *
 * @param {Array} array 需要查询的数组.
 * @param {Function} [predicate=_.identity] 判断条件.
 * @returns {Array} 返回切好的数组片段.
 * @example
 *
 * var users = [
 *   { 'user': 'barney',  'active': false },
 *   { 'user': 'fred',    'active': false },
 *   { 'user': 'pebbles', 'active': true }
 * ];
 *
 * _.takeWhile(users, function(o) { return !o.active; });
 * // => objects for ['barney', 'fred']
 *
 * // The `_.matches` iteratee shorthand.
 * _.takeWhile(users, { 'user': 'barney', 'active': false });
 * // => objects for ['barney']
 *
 * // The `_.matchesProperty` iteratee shorthand.
 * _.takeWhile(users, ['active', false]);
 * // => objects for ['barney', 'fred']
 *
 * // The `_.property` iteratee shorthand.
 * _.takeWhile(users, 'active');
 * // => []
 */
function takeWhile(array, predicate) {//但是,但是没有传入从右边开始
  return (array && array.length)
    ? baseWhile(array, baseIteratee(predicate, 3))
    : [];//
}

module.exports = takeWhile;

_.uniq(array)

创建一个数组包含原数组中的唯一值.

_.uniqBy(array, [iteratee=_.identity])

 和_.uniq很像,除了它接收一个遍历器被数组中的每个元素调用。

_.uniqWith(array, [comparator])

 和_.uniq很像,除了它接收一个比较方法被数组中的每个元素调用,比较方法接收两个参数(arrVal, othVal)

这三个方法依赖于baseUniq方法,先看源码

//_baseUniq.js

var SetCache = require('./_SetCache'),//Set缓存数组
    arrayIncludes = require('./_arrayIncludes'),//同Array.includes
    arrayIncludesWith = require('./_arrayIncludesWith'),//同Array.includes除了它接受一个比较方法
    cacheHas = require('./_cacheHas'),//判断缓存中是否含有某个元素
    createSet = require('./_createSet'),//创建Set对象
    setToArray = require('./_setToArray');//将Set对象转为数组

var LARGE_ARRAY_SIZE = 200;//大数组长度(用于数组过大时优化)

/**
 * _.uniqBy的基本实现,不支持遍历器的简写.
 *
 * @private
 * @param {Array} array 需要处理的数组.
 * @param {Function} [iteratee] 遍历器被每个元素调用.
 * @param {Function} [comparator] 比较器被每个元素 调用.
 * @returns {Array} 返回一个没有重复值得数组.
 */
function baseUniq(array, iteratee, comparator) {
  var index = -1,//数组索引
      includes = arrayIncludes,//是否包含
      length = array.length,//数组长度
      isCommon = true,//是否为常规比较
      result = [],//返回结果
      seen = result;//返回结果的引用(保存被遍历器调用过的值)

  if (comparator) {//如果有比较器,不是常规比较,并且比较方法为arrayIncludesWith
    isCommon = false;
    includes = arrayIncludesWith;
  }
  else if (length >= LARGE_ARRAY_SIZE) {//如果数组过长
    var set = iteratee ? null : createSet(array);
    if (set) {//如果没有传遍历器,只用转为Set对象,再转为数组,并将这个数组返回
      return setToArray(set);
    }
    //传了遍历器的情况

    isCommon = false;//也不是常规比较
    includes = cacheHas;//比较方法为cacheHas
    seen = new SetCache;//创建一个缓存数组
  }
  else {
    seen = iteratee ? [] : result;//如果有遍历器,seen为空数组,否则为result的引用
  }
  outer:
  //遍历数组
  while (++index < length) {
    var value = array[index],//当前元素
        computed = iteratee ? iteratee(value) : value;//如果有遍历器,对当前元素调用

    value = (comparator || value !== 0) ? value : 0;
    if (isCommon && computed === computed) {//常规情况,并且cumputed不为NaN
      var seenIndex = seen.length;//当前结果索引
      //遍历seen
      while (seenIndex--) {
          //如果当前结果中包含computed,跳过
        if (seen[seenIndex] === computed) {
          continue outer;
        }
      }
      if (iteratee) {//如果有遍历器,将computed添加到seen中
        seen.push(computed);
      }
      result.push(value);//将value添加到结果中
    }
    else if (!includes(seen, computed, comparator)) {//非常规比较
      if (seen !== result) {//如果seen为缓存,将computed添加到缓存中
        seen.push(computed);
      }
      result.push(value);//将value添加到结果中
    }
  }
  return result;//返回结果数组
}

module.exports = baseUniq;

对应的方法

uniq

//uniq.js

var baseUniq = require('./_baseUniq');//baseUniq方法

/**
 *
 * @param {Array} array 需要处理的数组.
 * @returns {Array} 返回一个没有重复值得数组.
 * @example
 *
 * _.uniq([2, 1, 2]);
 * // => [2, 1]
 */
function uniq(array) {
  return (array && array.length) ? baseUniq(array) : [];//不解释
}

module.exports = uniq;

uniqBy

//uniqBy.js

var baseIteratee = require('./_baseIteratee'),//遍历器封装
    baseUniq = require('./_baseUniq');//baseUniq方法

/**
 *
 *
 * @param {Array} array 需要处理的数组.
 * @param {Function} [iteratee=_.identity] 遍历器,被每个元素调用.
 * @returns {Array} 返回一个没有重复值得数组.
 * @example
 *
 * _.uniqBy([2.1, 1.2, 2.3], Math.floor);
 * // => [2.1, 1.2]
 *
 * // The `_.property` iteratee shorthand.
 * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
 * // => [{ 'x': 1 }, { 'x': 2 }]
 */
function uniqBy(array, iteratee) {
  return (array && array.length) ? baseUniq(array, baseIteratee(iteratee, 2)) : [];//不解释
}

module.exports = uniqBy;

uniqWith

//uniqWith.js

var baseUniq = require('./_baseUniq');//baseUniq方法

/**
 *
 *
 * @param {Array} array 需要处理的数组.
 * @param {Function} [comparator] 比较方法,被每个元素调用.
 * @returns {Array} 返回一个没有重复值得数组.
 * @example
 *
 * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
 *
 * _.uniqWith(objects, _.isEqual);
 * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
 */
function uniqWith(array, comparator) {
  comparator = typeof comparator == 'function' ? comparator : undefined;//比较器不为函数则为空
  return (array && array.length) ? baseUniq(array, undefined, comparator) : [];//不解释
}

module.exports = uniqWith;

_.union([arrays])

创建一个数组,包含给出的所有数组的值的唯一值.

//union.js

var baseFlatten = require('./_baseFlatten'),//数组扁平化(见源码学习(1))
    baseRest = require('./_baseRest'),//创建具备rest参数的方法
    baseUniq = require('./_baseUniq'),//baseUniq方法
    isArrayLikeObject = require('./isArrayLikeObject');//是否是类似数组的对象

/**
 *
 * @param {...Array} [arrays] 需要处理的数组.
 * @returns {Array} 返回一个没有重复值得数组.
 * @example
 *
 * _.union([2], [1, 2]);
 * // => [2, 1]
 */
var union = baseRest(function(arrays) {
    //先将给出的数组扁平化一级之后再调用baseUniq方法,并将结果作为返回值返回。
  return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
});

module.exports = union;

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

这个方法和_.union很像,除了它接收一个遍历器,被数组中的每个元素调用,遍历器接收一个参数(value)

//unionBy.js

var baseFlatten = require('./_baseFlatten'),//数组扁平化(见源码学习(1))
    baseIteratee = require('./_baseIteratee'),//遍历器封装
    baseRest = require('./_baseRest'),//创建具备rest参数的方法
    baseUniq = require('./_baseUniq'),//baseUniq方法
    isArrayLikeObject = require('./isArrayLikeObject'),//是否是类似数组的对象
    last = require('./last');//取得最后一个元素

/**
 *
 * @param {...Array} [arrays] 需要处理的数组.
 * @param {Function} [iteratee=_.identity] 遍历器,对每个元素调用.
 * @returns {Array} 返回一个没有重复值得数组.
 * @example
 *
 * _.unionBy([2.1], [1.2, 2.3], Math.floor);
 * // => [2.1, 1.2]
 *
 * // The `_.property` iteratee shorthand.
 * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
 * // => [{ 'x': 1 }, { 'x': 2 }]
 */
var unionBy = baseRest(function(arrays) {//创建可以使用rest参数的方法
  var iteratee = last(arrays);//遍历器为参数的最后一个
  if (isArrayLikeObject(iteratee)) {//如果是一个数组(就是没传),遍历器为undefined
    iteratee = undefined;
  }
  //先将给出的数组扁平化一级之后,并且将遍历器封装,再调用baseUniq方法,并将结果作为返回值返回。
  return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), baseIteratee(iteratee, 2));
});

module.exports = unionBy;

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

这个方法和_.union很像,除了它接收一个比较方法,被数组中的每个元素调用,比较方法接收两个参数(arrVal, othVal).

//uniqWith.js

var baseFlatten = require('./_baseFlatten'),//数组扁平化(见源码学习(1))
    baseRest = require('./_baseRest'),//创建具备rest参数的方法
    baseUniq = require('./_baseUniq'),//baseUniq方法
    isArrayLikeObject = require('./isArrayLikeObject'),//是否是类似数组的对象
    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 }];
 *
 * _.unionWith(objects, others, _.isEqual);
 * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
 */
var unionWith = baseRest(function(arrays) {//创建可以使用rest参数的方法
  var comparator = last(arrays);//比较方法为最后一个参数
  comparator = typeof comparator == 'function' ? comparator : undefined;//如果不是函数,比较方法为undefined
  //调用baseUniq方法,并将结果作为返回值返回。
  return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator);
});

module.exports = unionWith;

_.unzip(array)

_.zip的逆向,接收一个数组包含组合好的元素,然后创建一个数组重新分组这些元素到展开的状态

//unzip.js

var arrayFilter = require('./_arrayFilter'),//同Array.filter
    arrayMap = require('./_arrayMap'),//同Array.map
    baseProperty = require('./_baseProperty'),//通过key获取对象的value
    baseTimes = require('./_baseTimes'),//调用方法n次,返回包含每次结果的数组
    isArrayLikeObject = require('./isArrayLikeObject');//是否是一个类似数组的对象

var nativeMax = Math.max;//原生最小值方法

/**
 * 
 *
 * @param {Array} array 收起之后的数组.
 * @returns {Array} 返回展开之后的数组.
 * @example
 *
 * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]);
 * // => [['a', 1, true], ['b', 2, false]]
 *
 * _.unzip(zipped);
 * // => [['a', 'b'], [1, 2], [true, false]]
 */
function unzip(array) {
  if (!(array && array.length)) {//如果没有穿array,或者为空数组,返回空数组
    return [];
  }
  var length = 0;
  array = arrayFilter(array, function(group) {//返回array中,所有是数组的元素,并且取得length为最大的数组的长度
    if (isArrayLikeObject(group)) {
      length = nativeMax(group.length, length);
      return true;
    }
  });
  return baseTimes(length, function(index) {//调用length次方法,每次再调用map获得array中每个元素对应index位置的值得数组,然后将包含这些这些数组的数组返回。
    return arrayMap(array, baseProperty(index));
  });
}

module.exports = unzip;

_.unzipWith(array, [iteratee=_.identity])

这个方法和_.unzip很像,除了它接收一个遍历器决定怎么结合这些重组的元素,遍历器接收一个rest参数,表示每个分组中对应元素(...group)

//unzipWith.js


var apply = require('./_apply'),//同Function.apply
    arrayMap = require('./_arrayMap'),//同Array.map
    unzip = require('./unzip');//unzip方法

/**
 * 
 *
 * @param {Array} array 收起之后的数组.
 * @param {Function} [iteratee=_.identity] 遍历器,决定怎么结合这些元素
 * @returns {Array} 返回展开之后的数组.
 * @example
 *
 * var zipped = _.zip([1, 2], [10, 20], [100, 200]);
 * // => [[1, 10, 100], [2, 20, 200]]
 *
 * _.unzipWith(zipped, _.add);
 * // => [3, 30, 300]
 */
function unzipWith(array, iteratee) {
  if (!(array && array.length)) {//如果没有array或者为空数组,返回空数组
    return [];
  }
  var result = unzip(array);//调用unzip方法执行反压缩
  if (iteratee == null) {//如果没有传入便利器返回result
    return result;
  }
  return arrayMap(result, function(group) {//对结果进行遍历,每次调用iteratee传入每个group的所有元素,然后将处理后的结果作为每个分组的元素。
    return apply(iteratee, undefined, group);
  });
}

module.exports = unzipWith;

_.without(array, [values])

创建一个数组排除所有给定的值

//widthout.js

var baseDifference = require('./_baseDifference'),//取得数组中不包含过滤数组的元素(见源码学习(1))
    baseRest = require('./_baseRest'),//创建具备rest参数的数组
    isArrayLikeObject = require('./isArrayLikeObject');//是否是类似数组的对象

/**
 * 
 *
 * @param {Array} array 需要处理的数组.
 * @param {...*} [values] 需要排除的值.
 * @returns {Array} 返回过滤后的数组.
 * @example
 *
 * _.without([2, 1, 2, 3], 1, 2);
 * // => [3]
 */
var without = baseRest(function(array, values) {//创建具备rest参数的数组
    //如果是类似数组,调用baseDifference并将结果作为返回值返回,否则返回空数组
  return isArrayLikeObject(array)
    ? baseDifference(array, values)
    : [];
});

module.exports = without;

_.xor([arrays])

 创建一个唯一值得数组,包含给定所有数组中symmetric difference的集合(对差等分,{1,2,3}△{2,3,4} => {1,4})

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

这个方法和_.xor很像,除了它接收一个遍历器对每个元素调用,生成比较标准,遍历器接收一个参数(value)

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

 这个方法和_.xor很像,除了它接收一个比较器对每个元素调用,生成比较标准,比较器接收两个参数(arrVal,othVal)

这三个方法依赖于baseXor方法,先看源码

//_baseXor.js

var baseDifference = require('./_baseDifference'),//取得数组中不包含过滤数组的元素(见源码学习(1))
    baseFlatten = require('./_baseFlatten'),//数组扁平化(见源码学习(1))
    baseUniq = require('./_baseUniq');//得到数组中唯一值

/**
 * _.xor的基本实现,不支持遍历器的简写
 *
 * @private
 * @param {Array} arrays 需要处理的数组.
 * @param {Function} [iteratee] 遍历器被每个元素调用.
 * @param {Function} [comparator] 比较器被每个元素调用.
 * @returns {Array} 返回一个新的数组.
 */
function baseXor(arrays, iteratee, comparator) {
  var length = arrays.length;//数组长度
  if (length < 2) {//如果数组中元素个数小于2
    return length ? baseUniq(arrays[0]) : [];//如果有值得到第一个值得唯一值,否则空数组
  }
  var index = -1,//数组索引
      result = Array(length);//返回结果

  //遍历arrays
  while (++index < length) {
    var array = arrays[index],//当前数组
        othIndex = -1;//用于比较的数组的索引
    //遍历用于比较的数组
    while (++othIndex < length) {
      if (othIndex != index) {//如果比较的数组和当前数组不是同一个数组,调用baseDifference方法取得array中不同于当前用于比较的数组的值
        result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator);
      }
    }
  }
  //调用baseUiq方法,并且将result扁平化一级,然后将得到的唯一值数组返回
  return baseUniq(baseFlatten(result, 1), iteratee, comparator);
}

module.exports = baseXor;

对应的方法

xor

//xor.js

var arrayFilter = require('./_arrayFilter'),//同Array.filter
    baseRest = require('./_baseRest'),//创建具有rest参数的方法
    baseXor = require('./_baseXor'),//baseXor方法
    isArrayLikeObject = require('./isArrayLikeObject');//是否是类似数组的对象

/**
 *
 *
 * @param {...Array} [arrays] 需要处理的数组.
 * @returns {Array} 返回过滤后的数组.
 * @example
 *
 * _.xor([2, 1], [2, 3]);
 * // => [1, 3]
 */
var xor = baseRest(function(arrays) {//创建具有rest参数的方法
  return baseXor(arrayFilter(arrays, isArrayLikeObject));//调用baseXor并将结果作为返回值返回
});

module.exports = xor;

xorBy

//xorBy.js

var arrayFilter = require('./_arrayFilter'),//同Array.filter
    baseIteratee = require('./_baseIteratee'),//遍历器封装
    baseRest = require('./_baseRest'),//创建具备rest参数的方法
    baseXor = require('./_baseXor'),//baseXor方法
    isArrayLikeObject = require('./isArrayLikeObject'),//是否是一个类似数组的对象
    last = require('./last');//取得数组最后一个元素

/**
 *
 *
 * @param {...Array} [arrays] 需要处理的数组.
 * @param {Function} [iteratee=_.identity] 遍历器被每个元素调用.
 * @returns {Array} 返回过滤后的数组.
 * @example
 *
 * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor);
 * // => [1.2, 3.4]
 *
 * // The `_.property` iteratee shorthand.
 * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
 * // => [{ 'x': 2 }]
 */
var xorBy = baseRest(function(arrays) {//转化arrays为rest参数
  var iteratee = last(arrays);//遍历器为最后一个参数
  if (isArrayLikeObject(iteratee)) {//最后一个参数为数组,遍历器为undefined
    iteratee = undefined;
  }
  //调用baseXor并且封装遍历器,然后将结果作为返回值返回
  return baseXor(arrayFilter(arrays, isArrayLikeObject), baseIteratee(iteratee, 2));
});

module.exports = xorBy;

xorWith

//xorWith.js

var arrayFilter = require('./_arrayFilter'),//同Array.filter
    baseRest = require('./_baseRest'),//创建具备rest参数的方法
    baseXor = require('./_baseXor'),//baseXor方法
    isArrayLikeObject = require('./isArrayLikeObject'),//是否是一个类似数组的对象
    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 }];
 *
 * _.xorWith(objects, others, _.isEqual);
 * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
 */
var xorWith = baseRest(function(arrays) {//创建使用rest参数的方法
  var comparator = last(arrays);//比较器为最后一个参数
  comparator = typeof comparator == 'function' ? comparator : undefined;//比较器不是函数则为undefined
  //调用baseXor并且传入比较器,然后将结果作为返回值返回
  return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator);
});

module.exports = xorWith;

_.zip([arrays])

创建一个数组包含分组之后的元素,第一个元素为所有给出的数组的第一个元素,第二个元素为所有给出的数组的第二个元素,以此类推。

//zip.js

var baseRest = require('./_baseRest'),//创建具备rest参数的方法
    unzip = require('./unzip');//收起方法

/**
 * 
 *
 * @param {...Array} [arrays] 需要处理的数组.
 * @returns {Array} 返回收起之后的数组.
 * @example
 *
 * _.zip(['a', 'b'], [1, 2], [true, false]);
 * // => [['a', 1, true], ['b', 2, false]]
 */
var zip = baseRest(unzip);//创建unzip的rest参数模式

module.exports = zip;

_.zipObject([props=[]], [values=[]])

接收两个数组转化为对象,将第一个数组作为对象的属性,第二个作为对象的值,返回这个对象

这个方法依赖于baseZipObject和assignValue方法,assignValue方法依赖于baseAssignValue方法

baseZipObject

//_baseZipObject.js

/**
 * _.zipObject的基本实现,通过assignFunc进行赋值
 *
 * @param {Array} props 属性名.
 * @param {Array} values 属性值.
 * @param {Function} assignFunc 赋值方法.
 * @returns {Object} 返回新的对象.
 */
function baseZipObject(props, values, assignFunc) {
  var index = -1,//索引值
      length = props.length,//属性名个数
      valsLength = values.length,//属性值个数
      result = {};//返回结果对象

  while (++index < length) {//遍历属性名,如果对应的属性值没有则为undefined
    var value = index < valsLength ? values[index] : undefined;
    assignFunc(result, props[index], value);//使用赋值函数进行赋值
  }
  return result;//返回结果
}

module.exports = baseZipObject;

baseAssignValue

//_baseAssignValue.js

var defineProperty = require('./_defineProperty');//同Object.defineProperty

/**
 * assignValue方法和assignMergeValue的基本实现,不对值进行检查
 *
 * @private
 * @param {Object} object 需要修改的对象.
 * @param {string} key 赋值的key.
 * @param {*} value 赋值的value.
 */
function baseAssignValue(object, key, value) {
  if (key == '__proto__' && defineProperty) {//如果给__proto__赋值,使用defineProperty赋值
    defineProperty(object, key, {
      'configurable': true,
      'enumerable': true,
      'value': value,
      'writable': true
    });
  } else {//直接赋值
    object[key] = value;
  }
}

module.exports = baseAssignValue;

assignValue

//_assignValue.js

var baseAssignValue = require('./_baseAssignValue'),//baseAssignValue方法
    eq = require('./eq');//判断是否相等

var objectProto = Object.prototype;//对象的原型

var hasOwnProperty = objectProto.hasOwnProperty;//原生hasOwnProperty方法

/**
 * 对对象进行赋值,如果这个值不和本身对象中对象属性的值相同的话
 *
 * @private
 * @param {Object} object 需要修改的对象.
 * @param {string} key 辅助的key.
 * @param {*} value 赋值的value.
 */
function assignValue(object, key, value) {
  var objValue = object[key];//对象中对应属性的值
  if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
      (value === undefined && !(key in object))) {//如果属性不存在或者和本身的属性不相等,进行赋值操作
    baseAssignValue(object, key, value);
  }
}

module.exports = assignValue;

然后再看zipObject就比较清晰了

//zipObject.js

var assignValue = require('./_assignValue'),//赋值函数
    baseZipObject = require('./_baseZipObject');//baseZipObject方法

/**
 * 接收两个数组转化为对象,将第一个数组作为对象的属性,第二个作为对象的值,返回这个对象
 *
 * @param {Array} [props=[]] 属性名.
 * @param {Array} [values=[]] 属性值.
 * @returns {Object} 返回新的对象.
 * @example
 *
 * _.zipObject(['a', 'b'], [1, 2]);
 * // => { 'a': 1, 'b': 2 }
 */
function zipObject(props, values) {
  return baseZipObject(props || [], values || [], assignValue);//不解释
}

module.exports = zipObject;

_.zipObjectDeep([props=[]], [values=[]])

这个方法和_.zipObject很像,除了它支持使用属性的路径进行赋值

//zipObjectDeep.js

var baseSet = require('./_baseSet'),//赋值函数,支持使用属性路径(暂时不分析)
    baseZipObject = require('./_baseZipObject');//baseZipObject方法

/**
 * 
 *
 * @static
 * @memberOf _
 * @since 4.1.0
 * @category Array
 * @param {Array} [props=[]] 属性名.
 * @param {Array} [values=[]] 属性值.
 * @returns {Object} 返回新的对象.
 * @example
 *
 * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
 * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
 */
function zipObjectDeep(props, values) {
  return baseZipObject(props || [], values || [], baseSet);//不解释
}

module.exports = zipObjectDeep;

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

//zipWith.js

var baseRest = require('./_baseRest'),//创建具备rest参数的方法
    unzipWith = require('./unzipWith');//unzipWith方法。

/**
 * 这个方法和_.zip很像,除了它接收一个遍历器决定怎么结合这些重组的元素,遍历器接收一个rest参数,表示每个分组中对应元素(...group)
 *
 * @param {...Array} [arrays] 需要处理的数组.
 * @param {Function} [iteratee=_.identity] 遍历器,决定怎么结合这些元素
 *  grouped values.
 * @returns {Array} 返回收起之后的数组.
 * @example
 *
 * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) {
 *   return a + b + c;
 * });
 * // => [111, 222]
 */
var zipWith = baseRest(function(arrays) {//创建使用rest参数的方法
  var length = arrays.length,//参数长度
      iteratee = length > 1 ? arrays[length - 1] : undefined;//如果参数超过一个,遍历器为最后一个参数

  iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined;//如果遍历不为function,则为undefined
  return unzipWith(arrays, iteratee);//调用unzipWith方法,并将结果作为返回值返回。
});

module.exports = zipWith;

数组部分完结了,这些方法包含了很多对原生方法的重写,以及对数组的的各种遍历计算重组,通过学习这些方法感觉对数组的使用有了更深刻的认识。所以。。。继续加油吧。。。!

posted @ 2017-07-06 20:31  天下大雨  阅读(1702)  评论(0编辑  收藏  举报