0
点赞
收藏
分享

微信扫一扫

【lodash】difference源码研读解析【pre-index】

zhongjh 2022-02-26 阅读 40

一、环境准备

  • lodash 版本 v4.0.0

  • 通过 github1s 网页可以 查看 lodash - difference 源码

  • 调试测试用例可以 clone 到本地

git clone https://github.com/lodash/lodash.git

cd axios

npm install

npm run test

二、结构分析

difference_relation.jpg

  这是一张 difference 依赖引用路径图,相对复杂一些,按照功能划分,大致包括cache模块、index模块和flatten模块。接下来会自底向上分析各个依赖模块。由于依赖较多,篇幅较长,将按照模块分成四个部分,本篇主要讲述 Index 模块,包含 arrayIncludesbaseIndexOfbaseFindIndexbaseIsNaNstrictIndexOf

三、函数研读

1. strictIndexOf 模块

indexOf的一个特殊版本,它执行严格的相等用于比较value,比如===

/**
 * @private
 * @param {Array} array The array to inspect.
 * @param {*} value The value to search for.
 * @param {number} fromIndex The index to search from.
 * @returns {number} Returns the index of the matched value, else `-1`.
 */
function strictIndexOf(array, value, fromIndex) {
  let index = fromIndex - 1
  const { length } = array

  while (++index < length) {
    if (array[index] === value) {
      return index
    }
  }
  return -1
}

export default strictIndexOf
  • 重点关注MDN - Strict equality (===),全等运算符与相等运算符 == 最显著的区别是,如果操作数的类型不同,== 运算符会在比较之前尝试将它们转换为相同的类型。

2. baseIsNaN 模块

isNaN的基本实现,不支持数字对象

/**
 * @private
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
 */
function baseIsNaN(value) {
  return value !== value
}

export default baseIsNaN
  • 重点关注全局属性 NaN, NaN 的值表示不是一个数字(Not-A-Number),在现代浏览器中(ES5中), NaN 属性是一个不可配置(non-configurable),不可写(non-writable)的属性
  • 在执行自比较之中:NaN,也只有NaN,比较之中不等于它自己,NaN === NaN; // false

Tips:查找的内容有可能为 NaN,这时候使用严格查找 === 无法进行正确的比较,从而找不到 NaN,所以需要额外处理这种情况。

3. baseFindIndex 模块

findIndex和findLastIndex的基本实现

/**
 * @private
 * @param {Array} array The array to inspect.
 * @param {Function} predicate 每次迭代调用的函数
 * @param {number} fromIndex The index to search from.
 * @param {boolean} [fromRight] Specify iterating from right to left.
 * @returns {number} Returns the index of the matched value, else `-1`.
 */
function baseFindIndex(array, predicate, fromIndex, fromRight) {
  const { length } = array
  let index = fromIndex + (fromRight ? 1 : -1)

  while ((fromRight ? index-- : ++index < length)) {
    if (predicate(array[index], index, array)) {
      return index
    }
  }
  return -1
}

export default baseFindIndex
  • 重点关注 index = fromIndex + (fromRight ? 1 : -1) ,由于支持从右向左的迭代,起始index应该+1以防止index--越过0从而进入死循环,同理从左侧查起要确保查到array[0]从而起始 index 需要加一

4. baseIndexOf 模块

没有fromIndex边界检查的indexOf的基本实现

import baseFindIndex from './baseFindIndex.js'
import baseIsNaN from './baseIsNaN.js'
import strictIndexOf from './strictIndexOf.js'

/**
 * @private
 * @param {Array} array The array to inspect.
 * @param {*} value The value to search for.
 * @param {number} fromIndex The index to search from.
 * @returns {number} Returns the index of the matched value, else `-1`.
 */
function baseIndexOf(array, value, fromIndex) {
  return value === value
    ? strictIndexOf(array, value, fromIndex)
    : baseFindIndex(array, baseIsNaN, fromIndex)
}

export default baseIndexOf
  • value 如果不是 NaN,进入 strictIndexOf,从 array[fromIndex] 开始按序严格比较是否与 value 相等,若相等返回对应 index,否则返回 -1
  • value 如果是 NaN,进入 baseFindIndex,将 baseIsNaN 作为 baseFindIndex 的入参迭代函数 predicate 并开始从 array[fromIndex] 开始判断是否为 NaN,若找到 NaN 就返回对应 index,否则返回 -1

Tips:可以看到 baseFindIndex 模块中的有些形参是没有用到的,比如查找时是按照从左往右的顺序查找,并没有传入 fromRight,但提前占了坑,体现了很好的扩展性🐶

5. arrayIncludes 模块

不支持从数组指定位置搜索的includes

import baseIndexOf from './baseIndexOf.js'

/**
 * @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) {
  const length = array == null ? 0 : array.length
  return !!length && baseIndexOf(array, value, 0) > -1
}

export default arrayIncludes
  • 如果 length 不存在(包含null、0)或者没有找到 index 都会返回 false

Tips:!! 运算符表示逻辑非的取反运算,如!!objobj != null && typeof obj === undefined && obj != "" && obj != false 在计算上等价

举报

相关推荐

0 条评论