Skip to content

_.difference(array, [values]) #3

Open
@JCHappytime

Description

@JCHappytime

1. 作用及使用

创建一个具有唯一array值的数组,每个值不包含在其它给定的数组中。简单来说就是,检查第一个数组中的每个值,是否存在于第二个数组中,如果不存在则保留,存在则移除。
该方法使用SameValueZero做相等比较,结果值的顺序是由第一个数组中的顺序确定。
【参数】

  1. array: 要检查的数组
  2. [values]:排除的值(非必传)

2. 示例

1
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()方法的代码就不再贴出来了。

Metadata

Metadata

Assignees

No one assigned

    Labels

    数组数组相关的操作

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions