本章內容主要是:difference、baseDifference、isArrayLikeObject、isArrayLike、baseRest
Lodash是一個非常好用方便的JavaScript的工具庫,使得我們對數據處理能夠更加得心應手
接下來我要對Lodash的源碼進行剖析學習
每天幾個小方法,跟着我一起來學lodash吧
1、_.difference(array, [values])
根據中文文檔介紹,該函數就是可以將 array中的排除掉[values]中的元素,這是我個人的話語解釋,我們來看中文文檔解釋
以下是例子:
例子中我們輸入了兩個數組,第一個數組保持了存在的唯一值
接下來我們看源碼:
/**
* Creates an array of `array` values not included in the other given arrays
* using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* for equality comparisons. The order and references of result values are
* determined by the first array.
*
* **Note:** Unlike `_.pullAll`, this method returns a new array.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {Array} array The array to inspect.
* @param {...Array} [values] The values to exclude.
* @returns {Array} Returns the new array of filtered values.
* @see _.without, _.xor
* @example
*
* _.difference([2, 1], [2, 3]);
* // => [1]
*/
var difference = baseRest(function(array, values) {
return isArrayLikeObject(array)
? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
: [];
});
module.exports = difference;
一上來我們就可以看到還使用了其他的很多方法,就像我們昨天的老朋友:扁平化數組 baseFlatten
這裏的話 baseFlatten我就不過多介紹了
- baseDifference
/** Used as the size to enable large array optimizations. */
var LARGE_ARRAY_SIZE = 200;
/**
* The base implementation of methods like `_.difference` without support
* for excluding multiple arrays or iteratee shorthands.
*
* @private
* @param {Array} array The array to inspect.
* @param {Array} values The values to exclude.
* @param {Function} [iteratee] The iteratee invoked per element.
* @param {Function} [comparator] The comparator invoked per element.
* @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;
// 判斷如果數組的長度是 0,則返回空數組
if (!length) {
return result;
}
if (iteratee) {
values = arrayMap(values, baseUnary(iteratee));
}
if (comparator) {
includes = arrayIncludesWith;
isCommon = false;
}
// 當數組的長度大於 200 時執行,這是前面給出的常量。
else if (values.length >= LARGE_ARRAY_SIZE) {
includes = cacheHas;
isCommon = false;
values = new SetCache(values);
}
// 標籤語法
outer:
while (++index < length) {
var value = array[index],
// 當 iteratee == null 時返回 value,否則返回 iteratee(value)
computed = iteratee == null ? value : iteratee(value);
// 當 comparator 存在或者 value !==0 時,value = value
value = (comparator || value !== 0) ? value : 0;
if (isCommon && computed === computed) {
var valuesIndex = valuesLength;
while (valuesIndex--) {
if (values[valuesIndex] === computed) {
// 如果 values 中有值等於 computed,就退出到最外層的循環,這就是標籤語法的作用
continue outer;
}
}
result.push(value);
}
else if (!includes(values, computed, comparator)) {
result.push(value);
}
}
return result;
}
module.exports = baseDifference;
比如 baseDifference([1, 2], [2, 3, 4]) 這裏 array = [1, 2] , values = [2, 3, 4]
初始值 result = [], valuesLength = 3
for 遍歷,第一個值 value = 1, computed = 1, valuesIndex = 3;
values[2] = 4 !== value, values[1] = 3 !== value, values[0] = 2 !== value
result = [1]
接下來,遍歷第二個值, value = 2, computed = 2, vlauesIndex = 3;
values[2] = 4 !== value, values[1] = 3 !== value, values[0] = 2 == value
當存在值相等的時候,直接跳轉到最外層,所以 result = [1]
最後也就是說baseDifference([1, 2], [2, 3, 4]) = [1];
看到 outer:是不是一下子懵了,這就是標籤語法,形式是 label: statement,這裏的標籤可以是除了保留字以外的任意標識符,當然語句也可以是任意語句。它有什麼用呢?這個標籤就相當於一個定位符,在 break, continue 後面用於指定跳轉的位置。
作者:就想叫菜鳥
鏈接:https://www.jianshu.com/p/8946dc5d884e
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
沒錯,這個並非我的解釋,我覺得這位作者寫得挺好的就引用了一下
- isArrayLikeObject
/**
* This method is like `_.isArrayLike` except that it also checks if `value`
* is an object.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an array-like object,
* else `false`.
* @example
*
* _.isArrayLikeObject([1, 2, 3]);
* // => true
*
* _.isArrayLikeObject(document.body.children);
* // => true
*
* _.isArrayLikeObject('abc');
* // => false
*
* _.isArrayLikeObject(_.noop);
* // => false
*/
function isArrayLikeObject(value) {
return isObjectLike(value) && isArrayLike(value);
}
module.exports = isArrayLikeObject;
裏面又有一個isArrayLike的方法
- isArrayLike
/**
* Checks if `value` is array-like. A value is considered array-like if it's
* not a function and has a `value.length` that's an integer greater than or
* equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is array-like, else `false`.
* @example
*
* _.isArrayLike([1, 2, 3]);
* // => true
*
* _.isArrayLike(document.body.children);
* // => true
*
* _.isArrayLike('abc');
* // => true
*
* _.isArrayLike(_.noop);
* // => false
*/
function isArrayLike(value) {
return value != null && isLength(value.length) && !isFunction(value);
}
module.exports = isArrayLike;
isArrayLike方法比較簡單,你會發現裏面蹦出來個 isLength方法,這個我在這裏不過多介紹,是用來判斷數據長度是否是一個有限長度
所以總的來說 isArrayLikeObject是判斷我們輸入的數據是不是一個數組或類數組結構,是則返回true,反之false
- baseRest
/**
* The base implementation of `_.rest` which doesn't validate or coerce arguments.
*
* @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) {
return setToString(overRest(func, start, identity), func + '');
}
module.exports = baseRest;
這個函數主要是對剩餘參數的處理,它不用驗證參數或者強制輸入參數,這個我不過多解釋,大家理解就好
那麼搞了這麼久,我們終於可以解釋 difference方法發執行過程了,首先就是傳出參數並進行 baseRest剩餘參數處理,讓後就是直接輸出,我們首先判斷array是不是數組,如果不是則返回空數組,如果是則進行下一步,將我們的 [values]通過 baseFlatten方法一級扁平化處理,最後通過 baseDifference方法取出唯一值
今天雖然只寫了一個方法,但是它依賴的方法太多了,一起解釋了一遍,今天就這樣了,明天繼續