_.differenceBy(array, [values], [iteratee=_.identity])
與_.difference相比,它多接收一個iteratee參數。暫且稱之爲迭代器。web
_.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); }
顯然是以下的幾種解決字符串
identity
,返回第一個參數。
function identity(value) { return value; }
property
,返回屬性的值。
它的做用是
* var objects = [ * { 'a': { 'b': 2 } }, * { 'a': { 'b': 1 } } * ]; * * _.map(objects, _.property('a.b')); * // => [2, 1]
建立一個返回給定對象的 path 的值的函數。
這些又能夠總結開一章'lodash中的迭代器',咱們稍後再寫。