硬刚 lodash 源码之路,compact & concat
前置
本篇随笔包含 _.compact 和 _.concat 及其依赖的工具函数。
你可能需要一些 JavaScript 基础知识才能看懂一些没有注释的细节。
compact
_.compact(array)
创建一个新数组,包含原数组中所有的非假值元素。例如 false, null, 0, "", undefined, 和 NaN 都是被认为是“假值”。
/**
 * Creates an array with all falsey values removed. The values `false`, `null`,
 * `0`, `""`, `undefined`, and `NaN` are falsey.
 *
 * @since 0.1.0
 * @category Array
 * @param {Array} array The array to compact.
 * @returns {Array} Returns the new array of filtered values.
 * @example
 *
 * compact([0, 1, false, 2, '', 3])
 * // => [1, 2, 3]
 */
function compact(array) {
  let resIndex = 0
  const result = []
  if (array == null) {
    return result
  }
  // for of 循环 array
  // resIndex 自增赋值符合条件的数组
  for (const value of array) {
    if (value) {
      result[resIndex++] = value
    }
  }
  return result
}
export default compact
arrayPush
/**
 * Appends the elements of `values` to `array`.
 *
 * @private
 * @param {Array} array The array to modify.
 * @param {Array} values The values to append.
 * @returns {Array} Returns `array`.
 */
function arrayPush(array, values) {
  var index = -1,
      length = values.length,
      offset = array.length;
  // 循环往array结尾追加values的元素
  while (++index < length) {
    array[offset + index] = values[index];
  }
  return array;
}
module.exports = arrayPush;
对比 v8 的 push 实现:
// Appends the arguments to the end of the array and returns the new
// length of the array. See ECMA-262, section 15.4.4.7.
function ArrayPush() {
  CHECK_OBJECT_COERCIBLE(this, "Array.prototype.push");
  var array = TO_OBJECT(this);
  var n = TO_LENGTH(array.length); // 被push的array的length
  var m = arguments.length;
  // Subtract n from kMaxSafeInteger rather than testing m + n >
  // kMaxSafeInteger. n may already be kMaxSafeInteger. In that case adding
  // e.g., 1 would not be safe.
  if (m > kMaxSafeInteger - n) throw %make_type_error(kPushPastSafeLength, m, n);
  for (var i = 0; i < m; i++) {
    array[i+n] = arguments[i]; // 复制元素
  }
  var new_length = n + m; // // 修正length属性的值
  array.length = new_length;
  return new_length;
}
isObjectLike
检查 value 是否是类对象。如果一个值不是 null,并且 typeof 结果为 object,则该值为类对象。
/**
 * Checks if `value` is object-like. A value is object-like if it's not `null`
 * and has a `typeof` result of "object".
 *
 * @since 4.0.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
 * @example
 *
 * isObjectLike({})
 * // => true
 *
 * isObjectLike([1, 2, 3])
 * // => true
 *
 * isObjectLike(Function)
 * // => false
 *
 * isObjectLike(null)
 * // => false
 */
function isObjectLike(value) {
  return typeof value === 'object' && value !== null
}
export default isObjectLike
isArguments
import getTag from './.internal/getTag.js' // 在上一篇文章中解释了这个方法
import isObjectLike from './isObjectLike.js'
/**
 * Checks if `value` is likely an `arguments` object.
 *
 * @since 0.1.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is an `arguments` object, else `false`.
 * @example
 *
 * isArguments(function() { return arguments }())
 * // => true
 *
 * isArguments([1, 2, 3])
 * // => false
 */
function isArguments(value) {
  // 已经解释过 toStringTag
  return isObjectLike(value) && getTag(value) == '[object Arguments]'
}
export default isArguments
isFlattenable
检查  value 是否为可扁平化的 arguments 对象或数组。
import isArguments from '../isArguments.js'
/** Built-in value reference. */
const spreadableSymbol = Symbol.isConcatSpreadable
/**
 * Checks if `value` is a flattenable `arguments` object or array.
 *
 * @private
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
 */
function isFlattenable(value) {
  // Symbol.isConcatSpreadable 用于配置某对象作为 Array.prototype.concat() 方法的参数时是否展开其数组元素。
  // 参考 https://segmentfault.com/q/1010000021953491 的采纳答案
  return Array.isArray(value) || isArguments(value) ||
    !!(value && value[spreadableSymbol])
}
export default isFlattenable
baseFlatten
import isFlattenable from './isFlattenable.js'
/**
 * The base implementation of `flatten` with support for restricting flattening.
 *
 * @private
 * @param {Array} array The array to flatten. // 要扁平化的数组。
 * @param {number} depth The maximum recursion depth. // 最大递归深度。
 * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. // 每次迭代调用的函数。
 * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. // 只限于通过 "predicate"检查的数值。
 * @param {Array} [result=[]] The initial result value. // 初始结果值
 * @returns {Array} Returns the new flattened array. // 返回新的扁平化数组。
 */
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
}
export default baseFlatten
copyArray
/**
 * Copies the values of `source` to `array`.
 *
 * @private
 * @param {Array} source The array to copy values from.
 * @param {Array} [array=[]] The array to copy values to.
 * @returns {Array} Returns `array`.
 */
function copyArray(source, array) {
  let index = -1
  const length = source.length
  array || (array = new Array(length))
  while (++index < length) {
    array[index] = source[index]
  }
  return array
}
export default copyArray
isArray
/**
 * Checks if `value` is classified as an `Array` object.
 *
 * @static
 * @memberOf _
 * @since 0.1.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is an array, else `false`.
 * @example
 *
 * _.isArray([1, 2, 3]);
 * // => true
 *
 * _.isArray(document.body.children);
 * // => false
 *
 * _.isArray('abc');
 * // => false
 *
 * _.isArray(_.noop);
 * // => false
 */
var isArray = Array.isArray;
module.exports = isArray;
concat
_.concat(array, [values])
创建一个新数组,将 array 与任何数组或值连接在一起。
var arrayPush = require('./_arrayPush'),
    baseFlatten = require('./_baseFlatten'), // 扁平化数组
    copyArray = require('./_copyArray'),
    isArray = require('./isArray');
/**
 * Creates a new array concatenating `array` with any additional arrays
 * and/or values.
 *
 * @static
 * @memberOf _
 * @since 4.0.0
 * @category Array
 * @param {Array} array The array to concatenate.
 * @param {...*} [values] The values to concatenate.
 * @returns {Array} Returns the new concatenated array.
 * @example
 *
 * var array = [1];
 * var other = _.concat(array, 2, [3], [[4]]);
 *
 * console.log(other);
 * // => [1, 2, 3, [4]]
 *
 * console.log(array);
 * // => [1]
 */
function concat() {
  var length = arguments.length; // 参数数量
  if (!length) {
    return [];
  }
  var args = Array(length - 1), // [empty]
      array = arguments[0],  // 原数组
      index = length; 
  // args 加入除原数组以外的参数其他参数的数组或值
  while (index--) {
    args[index - 1] = arguments[index];
  }
  // 若原数组是 Array 类型,拷贝一遍数组返回,反之创建一个数组
  // 将 args 扁平化并 push 到原数组
  return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1));
}
module.exports = concat;
硬刚 lodash 源码之路,compact & concat的更多相关文章
- 硬刚 lodash 源码之路,_.chunk
		前置 chunk 函数内部借助其他函数实现,所以从其他函数开始,chunk 在最后. 你可能需要一些 JavaScript 基础知识才能看懂一些没有注释的细节. isObject 判断是否为 Obje ... 
- lodash源码分析之compact中的遍历
		小时候, 乡愁是一枚小小的邮票, 我在这头, 母亲在那头. 长大后,乡愁是一张窄窄的船票, 我在这头, 新娘在那头. 后来啊, 乡愁是一方矮矮的坟墓, 我在外头, 母亲在里头. 而现在, 乡愁是一湾浅 ... 
- 读lodash源码之从slice看稀疏数组与密集数组
		卑鄙是卑鄙者的通行证,高尚是高尚者的墓志铭. --北岛<回答> 看北岛就是从这两句诗开始的,高尚者已死,只剩卑鄙者在世间横行. 本文为读 lodash 源码的第一篇,后续文章会更新到这个仓 ... 
- lodash源码分析之chunk的尺与刀
		以不正义开始的事情,必须用罪恶使它巩固. --莎士比亚<麦克白> 最近很多事似乎印证了这句话,一句谎言最后要用一百句谎言来圆谎. 本文为读 lodash 源码的第二篇,后续文章会更新到这个 ... 
- lodash源码分析之Hash缓存
		在那小小的梦的暖阁,我为你收藏起整个季节的烟雨. --洛夫<灵河> 本文为读 lodash 源码的第四篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash gitbo ... 
- lodash源码分析之NaN不是NaN
		暗恋之纯粹,在于不求结果,完全把自己锁闭在一个单向的关系里面. --梁文道<暗恋到偷窥> 本文为读 lodash 源码的第五篇,后续文章会更新到这个仓库中,欢迎 star:pocket-l ... 
- lodash源码分析之自减的两种形式
		这个世界需要一个特定的恶人,可以供人们指名道姓,千夫所指:"全都怪你". --村上春树<当我谈跑步时我谈些什么> 本文为读 lodash 源码的第六篇,后续文章会更新到 ... 
- lodash源码分析之List缓存
		昨日我沿着河岸/漫步到/芦苇弯腰喝水的地方 顺便请烟囱/在天空为我写一封长长的信 潦是潦草了些/而我的心意/则明亮亦如你窗前的烛光/稍有暧昧之处/势所难免/因为风的缘故 --洛夫<因为风的缘故& ... 
- lodash源码分析之缓存方式的选择
		每个人心里都有一团火,路过的人只看到烟. --<至爱梵高·星空之谜> 本文为读 lodash 源码的第八篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash gitb ... 
随机推荐
- java实现矩形区域的交和并
			在编写图形界面软件的时候,经常会遇到处理两个矩形的关系. 如图[1.jpg]所示,矩形的交集指的是:两个矩形重叠区的矩形,当然也可能不存在(参看[2.jpg]).两个矩形的并集指的是:能包含这两个矩形 ... 
- java实现第六届蓝桥杯饮料换购
			饮料换购 饮料换购 乐羊羊饮料厂正在举办一次促销优惠活动.乐羊羊C型饮料,凭3个瓶盖可以再换一瓶C型饮料,并且可以一直循环下去,但不允许赊账. 请你计算一下,如果小明不浪费瓶盖,尽量地参加活动,那么, ... 
- 温故知新-多线程-深入刨析synchronized
			Posted by 微博@Yangsc_o 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0 文章目录 摘要 synchroniz ... 
- SpringCloud多数据源实现
			1.枚举多数据源-定义一一对应变量 /** * * 列出所有的数据源key(常用数据库名称来命名) * 注意: * 1)这里数据源与数据库是一对一的 * 2)DatabaseType中的变量名称就是数 ... 
- fedora gtk+ 2.0环境安装配置
			1.安装gtk yum install gtk2 gtk2-devel gtk2-devel-docs 2.测试是否安装成功 pkg-config --cflags --libs gtk+-2.0 执 ... 
- 油猴脚本 之 网教通直播评论记录抓取 v2.0
			先放一个 <油猴脚本 之 网教通直播评论记录抓取>那篇文章的传送门 . 修复内容 将所有表情转为 [符号表情] 字样,而非删除: 修复被禁言用户读取异常,现在被禁言用户表示为 张三 [已禁 ... 
- python获取本地时间戳
			import time print(time.time())#获当前时间的时间戳 print(time.localtime())#获取本地时间 print(time.strftime('%Y-%m-% ... 
- python基础--程序交互、格式化输出、流程控制、break、continue
			在此申明一下,博客参照了https://www.cnblogs.com/jin-xin/,自己做了部分的改动 (1) 程序交互 #!/usr/bin/env python # -*- coding: ... 
- jmeter组件中 测试计划,线程组,sampler等等
			[测试计划] 这边用户定义的变量,定义整个测试中使用的重复值(全局变量),一般定义服务器的ip,端口号 [线程组] 关于,线程组,我简单聊聊,有不对的地方欢迎大家拨乱反正 线程数:你需要运行的线程 比 ... 
- Bestcoder Round8
			4989Summary 既然用C++了就偷懒直接用STL大法了 #include<iostream> #include<algorithm> #include<vecto ... 
