前置

本篇随笔包含 _.compact_.concat 及其依赖的工具函数。

你可能需要一些 JavaScript 基础知识才能看懂一些没有注释的细节。

compact

  1. _.compact(array)

创建一个新数组,包含原数组中所有的非假值元素。例如 false, null, 0, "", undefined, 和 NaN 都是被认为是“假值”。

  1. /**
  2. * Creates an array with all falsey values removed. The values `false`, `null`,
  3. * `0`, `""`, `undefined`, and `NaN` are falsey.
  4. *
  5. * @since 0.1.0
  6. * @category Array
  7. * @param {Array} array The array to compact.
  8. * @returns {Array} Returns the new array of filtered values.
  9. * @example
  10. *
  11. * compact([0, 1, false, 2, '', 3])
  12. * // => [1, 2, 3]
  13. */
  14. function compact(array) {
  15. let resIndex = 0
  16. const result = []
  17. if (array == null) {
  18. return result
  19. }
  20. // for of 循环 array
  21. // resIndex 自增赋值符合条件的数组
  22. for (const value of array) {
  23. if (value) {
  24. result[resIndex++] = value
  25. }
  26. }
  27. return result
  28. }
  29. export default compact

arrayPush

  1. /**
  2. * Appends the elements of `values` to `array`.
  3. *
  4. * @private
  5. * @param {Array} array The array to modify.
  6. * @param {Array} values The values to append.
  7. * @returns {Array} Returns `array`.
  8. */
  9. function arrayPush(array, values) {
  10. var index = -1,
  11. length = values.length,
  12. offset = array.length;
  13. // 循环往array结尾追加values的元素
  14. while (++index < length) {
  15. array[offset + index] = values[index];
  16. }
  17. return array;
  18. }
  19. module.exports = arrayPush;

对比 v8 的 push 实现:

  1. // Appends the arguments to the end of the array and returns the new
  2. // length of the array. See ECMA-262, section 15.4.4.7.
  3. function ArrayPush() {
  4. CHECK_OBJECT_COERCIBLE(this, "Array.prototype.push");
  5. var array = TO_OBJECT(this);
  6. var n = TO_LENGTH(array.length); // 被push的array的length
  7. var m = arguments.length;
  8. // Subtract n from kMaxSafeInteger rather than testing m + n >
  9. // kMaxSafeInteger. n may already be kMaxSafeInteger. In that case adding
  10. // e.g., 1 would not be safe.
  11. if (m > kMaxSafeInteger - n) throw %make_type_error(kPushPastSafeLength, m, n);
  12. for (var i = 0; i < m; i++) {
  13. array[i+n] = arguments[i]; // 复制元素
  14. }
  15. var new_length = n + m; // // 修正length属性的值
  16. array.length = new_length;
  17. return new_length;
  18. }

isObjectLike

检查 value 是否是类对象。如果一个值不是 null,并且 typeof 结果为 object,则该值为类对象。

  1. /**
  2. * Checks if `value` is object-like. A value is object-like if it's not `null`
  3. * and has a `typeof` result of "object".
  4. *
  5. * @since 4.0.0
  6. * @category Lang
  7. * @param {*} value The value to check.
  8. * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
  9. * @example
  10. *
  11. * isObjectLike({})
  12. * // => true
  13. *
  14. * isObjectLike([1, 2, 3])
  15. * // => true
  16. *
  17. * isObjectLike(Function)
  18. * // => false
  19. *
  20. * isObjectLike(null)
  21. * // => false
  22. */
  23. function isObjectLike(value) {
  24. return typeof value === 'object' && value !== null
  25. }
  26. export default isObjectLike

isArguments

  1. import getTag from './.internal/getTag.js' // 在上一篇文章中解释了这个方法
  2. import isObjectLike from './isObjectLike.js'
  3. /**
  4. * Checks if `value` is likely an `arguments` object.
  5. *
  6. * @since 0.1.0
  7. * @category Lang
  8. * @param {*} value The value to check.
  9. * @returns {boolean} Returns `true` if `value` is an `arguments` object, else `false`.
  10. * @example
  11. *
  12. * isArguments(function() { return arguments }())
  13. * // => true
  14. *
  15. * isArguments([1, 2, 3])
  16. * // => false
  17. */
  18. function isArguments(value) {
  19. // 已经解释过 toStringTag
  20. return isObjectLike(value) && getTag(value) == '[object Arguments]'
  21. }
  22. export default isArguments

isFlattenable

检查 value 是否为可扁平化的 arguments 对象或数组。

  1. import isArguments from '../isArguments.js'
  2. /** Built-in value reference. */
  3. const spreadableSymbol = Symbol.isConcatSpreadable
  4. /**
  5. * Checks if `value` is a flattenable `arguments` object or array.
  6. *
  7. * @private
  8. * @param {*} value The value to check.
  9. * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
  10. */
  11. function isFlattenable(value) {
  12. // Symbol.isConcatSpreadable 用于配置某对象作为 Array.prototype.concat() 方法的参数时是否展开其数组元素。
  13. // 参考 https://segmentfault.com/q/1010000021953491 的采纳答案
  14. return Array.isArray(value) || isArguments(value) ||
  15. !!(value && value[spreadableSymbol])
  16. }
  17. export default isFlattenable

baseFlatten

  1. import isFlattenable from './isFlattenable.js'
  2. /**
  3. * The base implementation of `flatten` with support for restricting flattening.
  4. *
  5. * @private
  6. * @param {Array} array The array to flatten. // 要扁平化的数组。
  7. * @param {number} depth The maximum recursion depth. // 最大递归深度。
  8. * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. // 每次迭代调用的函数。
  9. * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. // 只限于通过 "predicate"检查的数值。
  10. * @param {Array} [result=[]] The initial result value. // 初始结果值
  11. * @returns {Array} Returns the new flattened array. // 返回新的扁平化数组。
  12. */
  13. function baseFlatten(array, depth, predicate, isStrict, result) {
  14. predicate || (predicate = isFlattenable)
  15. result || (result = [])
  16. if (array == null) {
  17. return result
  18. }
  19. for (const value of array) {
  20. if (depth > 0 && predicate(value)) {
  21. if (depth > 1) {
  22. // Recursively flatten arrays (susceptible to call stack limits).
  23. // 递归扁平化数组(易受调用栈限制)。
  24. baseFlatten(value, depth - 1, predicate, isStrict, result)
  25. } else {
  26. result.push(...value)
  27. }
  28. } else if (!isStrict) {
  29. result[result.length] = value
  30. }
  31. }
  32. return result
  33. }
  34. export default baseFlatten

copyArray

  1. /**
  2. * Copies the values of `source` to `array`.
  3. *
  4. * @private
  5. * @param {Array} source The array to copy values from.
  6. * @param {Array} [array=[]] The array to copy values to.
  7. * @returns {Array} Returns `array`.
  8. */
  9. function copyArray(source, array) {
  10. let index = -1
  11. const length = source.length
  12. array || (array = new Array(length))
  13. while (++index < length) {
  14. array[index] = source[index]
  15. }
  16. return array
  17. }
  18. export default copyArray

isArray

  1. /**
  2. * Checks if `value` is classified as an `Array` object.
  3. *
  4. * @static
  5. * @memberOf _
  6. * @since 0.1.0
  7. * @category Lang
  8. * @param {*} value The value to check.
  9. * @returns {boolean} Returns `true` if `value` is an array, else `false`.
  10. * @example
  11. *
  12. * _.isArray([1, 2, 3]);
  13. * // => true
  14. *
  15. * _.isArray(document.body.children);
  16. * // => false
  17. *
  18. * _.isArray('abc');
  19. * // => false
  20. *
  21. * _.isArray(_.noop);
  22. * // => false
  23. */
  24. var isArray = Array.isArray;
  25. module.exports = isArray;

concat

  1. _.concat(array, [values])

创建一个新数组,将 array 与任何数组或值连接在一起。

  1. var arrayPush = require('./_arrayPush'),
  2. baseFlatten = require('./_baseFlatten'), // 扁平化数组
  3. copyArray = require('./_copyArray'),
  4. isArray = require('./isArray');
  5. /**
  6. * Creates a new array concatenating `array` with any additional arrays
  7. * and/or values.
  8. *
  9. * @static
  10. * @memberOf _
  11. * @since 4.0.0
  12. * @category Array
  13. * @param {Array} array The array to concatenate.
  14. * @param {...*} [values] The values to concatenate.
  15. * @returns {Array} Returns the new concatenated array.
  16. * @example
  17. *
  18. * var array = [1];
  19. * var other = _.concat(array, 2, [3], [[4]]);
  20. *
  21. * console.log(other);
  22. * // => [1, 2, 3, [4]]
  23. *
  24. * console.log(array);
  25. * // => [1]
  26. */
  27. function concat() {
  28. var length = arguments.length; // 参数数量
  29. if (!length) {
  30. return [];
  31. }
  32. var args = Array(length - 1), // [empty]
  33. array = arguments[0], // 原数组
  34. index = length;
  35. // args 加入除原数组以外的参数其他参数的数组或值
  36. while (index--) {
  37. args[index - 1] = arguments[index];
  38. }
  39. // 若原数组是 Array 类型,拷贝一遍数组返回,反之创建一个数组
  40. // 将 args 扁平化并 push 到原数组
  41. return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1));
  42. }
  43. module.exports = concat;

硬刚 lodash 源码之路,compact & concat的更多相关文章

  1. 硬刚 lodash 源码之路,_.chunk

    前置 chunk 函数内部借助其他函数实现,所以从其他函数开始,chunk 在最后. 你可能需要一些 JavaScript 基础知识才能看懂一些没有注释的细节. isObject 判断是否为 Obje ...

  2. lodash源码分析之compact中的遍历

    小时候, 乡愁是一枚小小的邮票, 我在这头, 母亲在那头. 长大后,乡愁是一张窄窄的船票, 我在这头, 新娘在那头. 后来啊, 乡愁是一方矮矮的坟墓, 我在外头, 母亲在里头. 而现在, 乡愁是一湾浅 ...

  3. 读lodash源码之从slice看稀疏数组与密集数组

    卑鄙是卑鄙者的通行证,高尚是高尚者的墓志铭. --北岛<回答> 看北岛就是从这两句诗开始的,高尚者已死,只剩卑鄙者在世间横行. 本文为读 lodash 源码的第一篇,后续文章会更新到这个仓 ...

  4. lodash源码分析之chunk的尺与刀

    以不正义开始的事情,必须用罪恶使它巩固. --莎士比亚<麦克白> 最近很多事似乎印证了这句话,一句谎言最后要用一百句谎言来圆谎. 本文为读 lodash 源码的第二篇,后续文章会更新到这个 ...

  5. lodash源码分析之Hash缓存

    在那小小的梦的暖阁,我为你收藏起整个季节的烟雨. --洛夫<灵河> 本文为读 lodash 源码的第四篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash gitbo ...

  6. lodash源码分析之NaN不是NaN

    暗恋之纯粹,在于不求结果,完全把自己锁闭在一个单向的关系里面. --梁文道<暗恋到偷窥> 本文为读 lodash 源码的第五篇,后续文章会更新到这个仓库中,欢迎 star:pocket-l ...

  7. lodash源码分析之自减的两种形式

    这个世界需要一个特定的恶人,可以供人们指名道姓,千夫所指:"全都怪你". --村上春树<当我谈跑步时我谈些什么> 本文为读 lodash 源码的第六篇,后续文章会更新到 ...

  8. lodash源码分析之List缓存

    昨日我沿着河岸/漫步到/芦苇弯腰喝水的地方 顺便请烟囱/在天空为我写一封长长的信 潦是潦草了些/而我的心意/则明亮亦如你窗前的烛光/稍有暧昧之处/势所难免/因为风的缘故 --洛夫<因为风的缘故& ...

  9. lodash源码分析之缓存方式的选择

    每个人心里都有一团火,路过的人只看到烟. --<至爱梵高·星空之谜> 本文为读 lodash 源码的第八篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash gitb ...

随机推荐

  1. IDEA突然无法运行

    可能是你类的main方法被idea的智能提示改了 PS: 小编经常用智能提示,它给我把main方法的static关键字删掉了好几次,当时怎么也没想到是把main方法改了 ~难受

  2. Java实现8枚硬币问题(减治法)

    1 问题描述 在8枚外观相同的硬币中,有一枚是假币,并且已知假币与真币的重量不同,但不知道假币与真币相比较轻还是较重.可以通过一架天平来任意比较两组硬币,设计一个高效的算法来检测这枚假币. 2.1 减 ...

  3. java实现日程表

    [编程题] 某保密单位机要人员 A,B,C,D,E 每周需要工作5天,休息两天. 上级要求每个人每周的工作日和休息日必须是固定的,不能在周间变更. 此外,由于工作需要,还有如下要求: 1. 所有人的连 ...

  4. IDEA连接远程服务器Docker部署Spring Boot项目

    开始前的准备工作 拥有一台云服务器,我的是腾讯云服务器(CentOS7) 腾讯云服务器安装Docker,我的版本是Docker 19.03.9,关于安装和配置镜像加速器可以查阅我的另一篇博文:http ...

  5. cuda基础

    一:cuda编程模型 1:主机与设备 主机---CPU 设备/处理器---GPU CUDA编程模型如下: GPU多层存储空间结构如图: 2:Kernel函数的定义与调用 A:运行在GPU上,必须通过_ ...

  6. 2.keras-构建基本网络实现非线性回归

    构建基本网络实现非线性回归 1.加载显示数据集 import tensorflow as tf import numpy as np import keras from keras.layers im ...

  7. ASP.NET Core中间件与HttpModule有何不同

    前言 在ASP.NET Core中最大的更改之一是对Http请求管道的更改,在ASP.NET中我们了解HttpHandler和HttpModule但是到现在这些已经被替换为中间件那么下面我们来看一下他 ...

  8. ModelAndView的部分回顾

    ModelAndView的部分回顾 //@RestController @Controller //@SessionAttributes("user") //把modelandvi ...

  9. 掌握SpringBoot-2.3的容器探针:深入篇

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:原创分类汇总及配套源码,涉及Java.Docker.K8S.DevOPS等 关于<Spr ...

  10. mysql 双机互备份

    //1.创建用户CREATE USER 'dump'@'%' IDENTIFIED BY 'dump'; //2.开放权限GRANT ALL ON *.* TO 'dump'@'%'; //3.刷新权 ...