Open
Description
1. 作用及使用
创建一个具有唯一array值的数组,每个值不包含在其它给定的数组中。简单来说就是,检查第一个数组中的每个值,是否存在于第二个数组中,如果不存在则保留,存在则移除。
该方法使用SameValueZero做相等比较,结果值的顺序是由第一个数组中的顺序确定。
【参数】
- array: 要检查的数组
- [values]:排除的值(非必传)
2. 示例
3. 源码分析
源码:
function difference(array, ...values) {
return isArrayLikeObject(array)
? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
: []
}
这个函数中涉及到的isArrayLikeObject,baseDifference,baseFlatten分别如下:
- isArrayLikeObject (类数组的判断)
【作用】这个函数是为了判断array是否为数组,保证数组长度小于最大值。
function isArrayLikeObject(value) {
return (typeof value === 'object' && value !== null) && (value != null && typeof value !== 'function' && isLength(value.length));
}
function isLength(value) {
return typeof value === 'number' &&
value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; // MAX_SAFE_INTEGER=9007199254740991
}
- baseDifference
这个方法才是我们要研究的关键所在。
function baseDifference(array, values, iteratee, comparator) {
let includes = arrayIncludes
let isCommon = true
const result = []
const valuesLength = values.length
if (!array.length) {
return result
}
if (iteratee) {
values = map(values, (value) => iteratee(value))
}
if (comparator) {
includes = arrayIncludesWith
isCommon = false
}
else if (values.length >= LARGE_ARRAY_SIZE) {
includes = cacheHas
isCommon = false
values = new SetCache(values)
}
outer:
for (let value of array) {
const computed = iteratee == null ? value : iteratee(value)
value = (comparator || value !== 0) ? value : 0
if (isCommon && computed === computed) {
let valuesIndex = valuesLength
while (valuesIndex--) {
if (values[valuesIndex] === computed) {
continue outer
}
}
result.push(value)
}
else if (!includes(values, computed, comparator)) {
result.push(value)
}
}
return result
}
- baseFlatten
function baseFlatten(array, depth, predicate, isStrict, result) {
predicate || (predicate = isFlattenable)
result || (result = [])
if (array == null) {
return result
}
for (const value of array) {
if (depth > 0 && predicate(value)) {
if (depth > 1) {
// Recursively flatten arrays (susceptible to call stack limits).
baseFlatten(value, depth - 1, predicate, isStrict, result)
} else {
result.push(...value)
}
} else if (!isStrict) {
result[result.length] = value
}
}
return result
}
function isFlattenable(value) {
return Array.isArray(value) || isArguments(value) ||
!!(value && value[spreadableSymbol])
}
这里的isArguments()方法的代码就不再贴出来了。