天天一個lodash方法-differenceBy

differenceBy

用法

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

功能

與_.difference相比,它多接收一個iteratee參數。暫且稱之爲迭代器。web

demo

_.differenceBy([3.1, 2.2, 1.3], [4.4, 2.5], Math.floor);

源碼

上兩篇已經涉及過相關的代碼,還是在baseDifference數組

function baseDifference(array, values, iteratee, comparator) {
  var index = -1,
      includes = arrayIncludes,//方法。
      isCommon = true,
      length = array.length,
      result = [],
      valuesLength = values.length;

  if (!length) {
    return result;
  }
  if (iteratee) { // 迭代器函數。 

    values = arrayMap(values, baseUnary(iteratee)); // 這裏提早處理下  while循環裏邊有個判段,這裏提早就遍歷,處理數據。
  }
  if (comparator) { //comparator存在,includes從arrayIncludes =》arrayIncludesWith,
    includes = arrayIncludesWith;
    isCommon = false;
  }
  else if (values.length >= LARGE_ARRAY_SIZE) {
    //- 大型數組的優化,這裏默認理解爲超過200就是大數組。大的數組啓用緩存。
    includes = cacheHas; // includes方法設置爲cacheHas處理,這裏也是作緩存
    isCommon = false;//標示  不是普通方式處理了
    values = new SetCache(values);
  }
  outer:
   //切記,比對的是array,values
  while (++index < length) {
    var value = array[index],//array的一個element
        computed = iteratee ? iteratee(value) : value;//若是有迭代器,就處理成爲computed

    value = (comparator || value !== 0) ? value : 0;
    if (isCommon && computed === computed) { // 取出來的數據不是NaN
      var valuesIndex = values.length;
      while (valuesIndex--) {
        if (values[valuesIndex] === computed) {
          continue outer; //跳會outer,繼續執行  由於是求差集,也就是value中的元素,在array不能存在。 這裏有相同,array中的當前元素就不該該在結果集裏出現。
        }
      }
      result.push(value);
    }
    else if (!includes(values, computed, comparator)) {
      result.push(value);
    }
  }
  return result;
}

須要注意的代碼片斷緩存

if (iteratee) { // 迭代器函數。 

    values = arrayMap(values, baseUnary(iteratee)); // 
  }

便於思考,此時的differenceBy傳入了三個參數array,values,iteratee,在當前代碼片斷已經經過arrayMap(values, baseUnary(iteratee)),已經遍歷使用iteratee,返回的values更像是一個結果集。 ide

爲什麼提早調用。在最終的while循環中,還要遍歷array,調用iteratee 進行比對。顯然內層仍然須要一個遍歷,可是咱們不但願每一個遍歷再去調用一次迭代器。在外層一次處理,開銷遠遠每次在其中調用。函數

篩選出結果的部分,優化

while (++index < length) {
    var value = array[index],//array的一個element
        computed = iteratee ? iteratee(value) : value;//若是有迭代器,就處理成爲computed

    value = (comparator || value !== 0) ? value : 0;
    if (isCommon && computed === computed) { // 取出來的數據不是NaN
      var valuesIndex = values.length;
      while (valuesIndex--) {
        if (values[valuesIndex] === computed) {
          continue outer; //跳會outer,繼續執行  由於是求差集,也就是value中的元素,在array不能存在。 這裏有相同,array中的當前元素就不該該在結果集裏出現。
        }
      }
      result.push(value);
    }
    //不會執行下邊的邏輯。
    else if (!includes(values, computed, comparator)) {
      result.push(value);
    }
  }

這不是結束的好時候

寫到這,在官網提供的demo裏,有以下的code

_.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
// => [{ 'x': 2 }]

這裏的iteratee,傳入的是一個字符串x,咱們大概知道它是什麼什麼意思,比對,對象的x的值。對象

咱們能夠推想,對於iteratee,咱們會根據它不一樣的類型包裝成不一樣的函數,lodash中相關代碼以下element

baseIteratee(iteratee, 2)
function baseIteratee(value) {
  // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
  // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
  if (typeof value == 'function') {
    return value;
  }
  if (value == null) {
    return identity;
  }
  if (typeof value == 'object') {
    return isArray(value)
      ? baseMatchesProperty(value[0], value[1])
      : baseMatches(value);
  }
  return property(value);
}

顯然是以下的幾種解決字符串

  • value若是是函數,直接返回
  • 若是是null,返回identity
  • 若是是Object 又會根據是不是數組,返回不一樣的。
  • 以上都不屬於,直接返回property(value)

identity,返回第一個參數。

function identity(value) {
  return value;
}

property,返回屬性的值。

它的做用是

* var objects = [
 *   { 'a': { 'b': 2 } },
 *   { 'a': { 'b': 1 } }
 * ];
 *
 * _.map(objects, _.property('a.b'));
 * // => [2, 1]

建立一個返回給定對象的 path 的值的函數。

這些又能夠總結開一章'lodash中的迭代器',咱們稍後再寫。

相關文章
相關標籤/搜索