建立一個具備惟一array值的數組,每一個值不包含在其餘給定的數組中。數組
_.difference([3, 2, 1], [4, 2]); // => [3, 1]
var difference = baseRest(function(array, values) { return isArrayLikeObject(array) ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) : []; });
該方法用到了baseReset
方法。它接收的參數是一個匿名函數,匿名函數內接收兩個參數,一個是array數組
,另外一個就是defference的兩個參數緩存
/** * The base implementation of `_.rest` which doesn't validate or coerce arguments. * _.reset的基本實現,可是不會校驗或者corce參數。 * @private * @param {Function} func The function to apply a rest parameter to. * @param {number} [start=func.length-1] The start position of the rest parameter. * @returns {Function} Returns the new function. */ function baseRest(func, start) { // start = undefined start = nativeMax(start === undefined ? (func.length - 1) : start, 0); // var nativeMax = Math.max; return function() { var args = arguments, index = -1, length = nativeMax(args.length - start, 0), array = Array(length); while (++index < length) { array[index] = args[start + index]; } index = -1; var otherArgs = Array(start + 1); while (++index < start) { otherArgs[index] = args[index]; } otherArgs[start] = array; return apply(func, this, otherArgs); }; }
baseReset
是_.rest
方法(建立一個函數,調用func時,this綁定到建立的新函數,而且start以後的參數做爲數組傳入。)的基礎實現。閉包
看一下它執行的效果。app
var say = _.rest(function(what, names) { return what + ' ' + _.initial(names).join(', ') + (_.size(names) > 1 ? ', & ' : '') + _.last(names); }); say('hello', 'fred', 'barney', 'pebbles'); // => 'hello fred, barney, & pebbles'
_.rest
,傳入一個匿名函數,返回一個新函數,並賦值給了say
,say('hello', 'fred', 'barney', 'pebbles')
,其中hello
對應的是what
,剩餘的參數對應的是names
。函數
再回到baseReset
.源碼分析
(往上看好煩啊,我copy了返回的函數到下邊)優化
// func函數 ,start=0 return function() { // arguments 就像上文say函數調用時傳入的參數,假設此時傳入了6個參數,[a,b,c,d,e,f] var args = arguments,//args.length = 6 index = -1, length = nativeMax(args.length - start, 0),//6 array = Array(length);// array爲長度爲6的數組, while (++index < length) { // 0,1,2,3,4,5 <6 array[index] = args[start + index]; // arr[0] = args[0+0],arr[1]= args[0+1] } // finally 6個長度的數組`array` array = [a,b,c,d,e,f] index = -1; // 重置index = -1 var otherArgs = Array(start + 1); // otherArgs 爲一個長度的數組 [] length = 1 while (++index < start) { otherArgs[index] = args[index];// otherArgs = 取出args[0] } otherArgs[start] = array;// otherArgs[0] = [a,b,c,d,e,f] return apply(func, this, otherArgs); // apply執行 };
此處apply
比原生的apply速度更快,做用跟原生js的apply用法和做用是同樣的。this
function apply(func, thisArg, args) { switch (args.length) { case 0: return func.call(thisArg); case 1: return func.call(thisArg, args[0]); case 2: return func.call(thisArg, args[0], args[1]); case 3: return func.call(thisArg, args[0], args[1], args[2]); } return func.apply(thisArg, args); }
注意: while中的i++和 ++i的區別,++i是先算值再判斷符合條件,i++則是先判斷是否符合條件,再自增。rest
difference
的關鍵代碼就是這段.code
baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
接下來天然要看baseDifference
,baseFlatten
.
baseFlatten
在concat一篇中
已經出現過了,是用來打平多維數組。
接下倆看baseDifference
** * -.difference的基本實現。 * * @private * @param {Array} array The array to inspect. 須要被檢查的數組 * @param {Array} values The values to exclude. 須要被排除出去的數組 * @param {Function} [iteratee] The iteratee invoked per element. 迭代器函數,調用每一個element * @param {Function} [comparator] The comparator invoked per element. 比較器,也會調用每一個ele * @returns {Array} Returns the new array of filtered values. 返回被過濾調的新的數組 */ 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) { // 迭代器函數。 這裏須要研究arrayMap 和baseUnary方法了 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 = valuesLength; 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; }
普通的處理方式相對好處理一些。isCommon
用來標示是否使用普通處理。爲了作優化,做者顯然作了更多。有兩種狀況須要作優化
incluedes=arrayIncludesWith
incluedes=cacheHas
,`values = new SetCache(values);else if (!includes(values, computed, comparator)) { result.push(value); }
非正常狀況下作的處理代碼。
這塊詳細說,代碼就太長了再開一篇吧。
/** * 數組中Array是否包含 value , * @private * @param {Array} [array] The array to inspect. * @param {*} target The value to search for. * @returns {boolean} Returns `true` if `target` is found, else `false`. */ function arrayIncludes(array, value) { var length = array ? array.length : 0; return !!length && baseIndexOf(array, value, 0) > -1; } // arrayIncludes(["123"],"123") => true
/** * The base implementation of `_.indexOf` without `fromIndex` bounds checks. * _.indexOf的基本實現,沒有fromIndex的邊界檢查 * @private * @param {Array} array The array to inspect. 被檢查的數組 * @param {*} value The value to search for. 被查找的值 * @param {number} fromIndex The index to search from. 從哪一個位置開始search * @returns {number} Returns the index of the matched value, else `-1`. */ function baseIndexOf(array, value, fromIndex) { if (value !== value) { //NaN就調用baseFindIndex return baseFindIndex(array, baseIsNaN, fromIndex); } var index = fromIndex - 1, // -1 length = array.length; // while (++index < length) { if (array[index] === value) { return index; //遍歷判斷結果,有符合條件 返回index,不然爲-1 } } return -1; }
/** * A specialized version of `_.map` for arrays without support for iteratee * shorthands. * * @private * @param {Array} [array] The array to iterate over. 用來被遍歷的數組 * @param {Function} iteratee The function invoked per iteration. 迭代器 * @returns {Array} Returns the new mapped array. */ function arrayMap(array, iteratee) { var index = -1, length = array ? array.length : 0, result = Array(length); //結果數組 while (++index < length) { result[index] = iteratee(array[index], index, array); // 這裏就遍歷了數據,返回遍歷的結果。 } return result; }
/** * 建立一個最多接受一個參數的函數,忽略多餘的參數。 * * @private * @param {Function} func The function to cap arguments for. * @returns {Function} Returns the new capped function. */ function baseUnary(func) { return function(value) { return func(value); }; }