giscafer / giscafer.github.io

giscafer's blog
http://blog.giscafer.com
10 stars 5 forks source link

lodash源码学习—— Array之 drop 、dropRight、dropRightWhile、dropWhile函数 #33

Open giscafer opened 6 years ago

giscafer commented 6 years ago

本篇学习的是_.drop_.dropRight 、_.dropWhile` 等函数

源码依赖大致关系

_.drop
_.dropRight
   | slice.js

_.dropWhile
_.dropRightWhile
   | .internal
               |--baseWhile.js

源码学习

drop.js

import slice from './slice.js'

/**
 * Creates a slice of `array` with `n` elements dropped from the beginning.
 * 
 * 从左到右,从第n个元素算起,截取数组`array`元素。
 *
 * @since 0.5.0
 * @category Array
 * @param {Array} array The array to query.
 * @param {number} [n=1] 截取元素的位置,默认1.
 * @returns {Array} Returns the slice of `array`.
 * @example
 *
 * drop([1, 2, 3])
 * // => [2, 3]
 *
 * drop([1, 2, 3], 2)
 * // => [3]
 *
 * drop([1, 2, 3], 5)
 * // => []
 *
 * drop([1, 2, 3], 0)
 * // => [1, 2, 3]
 */
function drop(array, n=1) {
  // 数组判空
  const length = array == null ? 0 : array.length;
  // 使用slice截取数组
  return length
    ? slice(array, n < 0 ? 0 : n, length)
    : []
}

export default drop

dropRight.js

drop函数差不多,方向不一样。

import slice from './slice.js'

/**
 * Creates a slice of `array` with `n` elements dropped from the end.
 * 从右向左,从第n个元素算起,截取数组`array`元素
 * 
 * @since 3.0.0
 * @category Array
 * @param {Array} array The array to query.
 * @param {number} [n=1] 截取元素的位置,默认1.
 * @returns {Array} Returns the slice of `array`.
 * @example
 *
 * dropRight([1, 2, 3])
 * // => [1, 2]
 *
 * dropRight([1, 2, 3], 2)
 * // => [1]
 *
 * dropRight([1, 2, 3], 5)
 * // => []
 *
 * dropRight([1, 2, 3], 0)
 * // => [1, 2, 3]
 */
function dropRight(array, n=1) {
  const length = array == null ? 0 : array.length
  return length ? slice(array, 0, n < 0 ? 0 : -n) : []
}

export default dropRight

dropWhile.js

核心为baseWhile,见下边

import baseWhile from './.internal/baseWhile.js'

/**
 * Creates a slice of `array` excluding elements dropped from the beginning.
 * Elements are dropped until `predicate` returns falsey. The predicate is
 * invoked with three arguments: (value, index, array).
 *
 * @since 3.0.0
 * @category Array
 * @param {Array} array The array to query.
 * @param {Function} predicate The function invoked per iteration.
 * @returns {Array} Returns the slice of `array`.
 * @example
 *
 * const users = [
 *   { 'user': 'barney',  'active': true },
 *   { 'user': 'fred',    'active': true },
 *   { 'user': 'pebbles', 'active': false }
 * ]
 *
 * dropWhile(users, ({ active }) => active)
 * // => objects for ['pebbles']
 */
function dropWhile(array, predicate) {
  return (array != null && array.length)
    ? baseWhile(array, predicate, true)
    : []
}

export default dropWhile

dropRightWhile.js

核心为baseWhile,见下边

import baseWhile from './.internal/baseWhile.js'

/**
 * Creates a slice of `array` excluding elements dropped from the end.
 * Elements are dropped until `predicate` returns falsey. The predicate is
 * invoked with three arguments: (value, index, array).
 * 
 * 从右向左,从第n个元素算起,截取数组`array`元素。回调函数`predicate`返回值为falsey才截取。predicate函数参数为(value, index, array)
 * 
 *
 * @since 3.0.0
 * @category Array
 * @param {Array} array The array to query.
 * @param {Function} predicate The function invoked per iteration.
 * @returns {Array} Returns the slice of `array`.
 * @example
 *
 * const users = [
 *   { 'user': 'barney',  'active': false },
 *   { 'user': 'fred',    'active': true },
 *   { 'user': 'pebbles', 'active': true }
 * ]
 *
 * dropRightWhile(users, ({ active }) => active)
 * // => objects for ['barney']
 */
function dropRightWhile(array, predicate) {
  return (array != null && array.length)
    ? baseWhile(array, predicate, true, true)
    : []
}

export default dropRightWhile

baseWhile.js

import slice from '../slice.js'

/**
 * The base implementation of methods like `dropWhile` and `takeWhile`.
 * 
 * `dropWhile` 和 `takeWhile` 方法的基本实现
 *
 * @private
 * @param {Array} array 查询数组
 * @param {Function} predicate 每次循环执行的函数.
 * @param {boolean} [isDrop] 舍弃元素而不是替换他们
 * @param {boolean} [fromRight] 是否为从右向左遍历
 * @returns {Array} Returns the slice of `array`.
 */
function baseWhile(array, predicate, isDrop, fromRight) {
  const { length } = array
  let index = fromRight ? length : -1

  // 循环直到predicate返回false或循环结束
  // (fromRight ? index-- : ++index < length) 很精简,index--为0的时候或++index>=length的时候退出循环
  while ((fromRight ? index-- : ++index < length) && predicate(array[index], index, array)) {
  }
  return isDrop
    ? slice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length))
    : slice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index))
}

export default baseWhile

总结

lodash 的 函数基本设计思想都是具备一个基本功能实现函数(这里我称基实现,如baseXXX),然后基于基实现函数,扩展出各种相近功能点但不同作用的函数。大部分核心精华代码也在基实现函数中。 如以上的所有代码,baseWhile.js代码就比较精简。


源码注释+测试代码见lodash-sourcecode-study 前端学堂:felearn.com