[lodash] difference source code study and analysis [pre index]

Posted by mastermike707 on Sat, 26 Feb 2022 15:15:05 +0100

Welcome to my official account, "front-end wall".

A modern JavaScript utility library delivering modularity, performance & extras.

lodash is a consistent, modular, high-performance JavaScript utility library

1, Environmental preparation

  • lodash version v4 zero

  • Through github1s web page, you can see lodash - difference source code

  • Debug test cases can be clone d locally

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

cd axios

npm install

npm run test

2, Structural analysis

   this is a difference dependency reference path diagram, which is relatively complex. According to the function, it roughly includes cache module, Index module and flatten module. Next, we will analyze each dependent module from the bottom up. Due to the large number of dependencies and long length, it will be divided into four parts according to the module. This article mainly describes the Index module, including arrayIncludes, baseIndexOf, baseFindIndex, baseIsNaN and strictIndexOf.

3, Function study

1. strictIndexOf module

A special version of indexOf that performs strict equality and is used to compare value s, such as===

/**
 * @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
  • Focus on MDN - Strict equality (===) , the most significant difference between the congruence operator and the equality operator = = is that if the operands are of different types, the = = operator attempts to convert them to the same type before comparison.

2. baseIsNaN module

The basic implementation of isNaN does not support digital objects

/**
 * @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
  • Focus on global attributes NaN , the value of NaN indicates that it is not a number (Not-A-Number). In modern browsers (ES5), the NaN attribute is a non configurable and non writable attribute
  • In the self comparison: NaN, there is only NaN. In the comparison, it is not equal to itself, NaN = = = NaN// false

Tips: the search content may be NaN. In this case, strict search = = = cannot be used for correct comparison, so NaN cannot be found, so it needs to be handled additionally.

3. baseFindIndex module

Basic implementation of findIndex and findLastIndex

/**
 * @private
 * @param {Array} array The array to inspect.
 * @param {Function} predicate Function called per iteration
 * @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
  • Focus on index = fromindex + (fromlight? 1: - 1). Since the iteration from right to left is supported, the starting index should be + 1 to prevent index -- from crossing 0 and entering the dead cycle. Similarly, from the left, make sure that array[0] is found, so the starting index needs to be increased by one

4. baseIndexOf module

Basic implementation of indexOf without fromIndex boundary check

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
  • If value is not NaN, enter strictIndexOf, and strictly compare whether it is equal to value in sequence from array[fromIndex]. If it is equal, return the corresponding index, otherwise return - 1
  • If value is NaN, enter baseFindIndex, take baseIsNaN as the input parameter of baseFindIndex, iterate the function predict, and start judging whether it is NaN from array[fromIndex]. If NaN is found, return the corresponding index, otherwise return - 1

Tips: you can see that some formal parameters in the baseFindIndex module are not used. For example, when searching, they are searched from left to right. No fromlight is passed in, but the pit is occupied in advance, which reflects good scalability 🐶

5. arrayIncludes module

includes searched from the specified position in the array is not supported

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
  • If length does not exist (including null and 0) or index is not found, false will be returned

Tips: !! Operator represents the negation of logical non, such as!! Obj and obj= null && typeof obj === undefined && obj != "" && obj != False is computationally equivalent

Topics: Javascript Front-end source code Lodash