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;

數組部分完結了,這些方法包含了很多對原生方法的重寫,以及對數組的的各種遍歷計算重組,通過學習這些方法感覺對數組的使用有了更深刻的認識。所以。。。繼續加油吧。。。!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM