前置

本篇随笔包含 _.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的更多相关文章

  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. Java实现 LeetCode 128 最长连续序列

    128. 最长连续序列 给定一个未排序的整数数组,找出最长连续序列的长度. 要求算法的时间复杂度为 O(n). 示例: 输入: [100, 4, 200, 1, 3, 2] 输出: 4 解释: 最长连 ...

  2. Java实现回文判断

    1 问题描述 给定一个字符串,如何判断这个字符串是否是回文串? 所谓回文串,是指正读和反读都一样的字符串,如madam.我爱我等. 2 解决方案 解决上述问题,有两种方法可供参考: (1)从字符串两头 ...

  3. CDN百科第三讲 | 如果用了云服务器,还需要做CDN加速吗?

    在全站上云的背景下,云计算已经不仅仅是大型互联网公司的独享概念,正在被更多的传统企业.中小企业甚至个人站长所采用.在众多云计算服务中,最常见两个产品就是云服务器和CDN,今天的CDN百科第三讲,就给大 ...

  4. 一文讲透Java序列化

    本文目录 一.序列化是什么 二.为什么需要序列化 三.序列化怎么用 四.序列化深度探秘 4.1 为什么必须实现Serializable接口 4.2 被序列化对象的字段是引用时该怎么办 4.3 同一个对 ...

  5. ES 复合查询

    ES在查询过程中比较多遇到符合查询,既需要多个字段过滤也需要特殊情况处理,本文简单介绍几种查询组合方便快捷查询ES. bool布尔查询有一个或者多个布尔子句组成     filter 只过滤符合条件的 ...

  6. 00-01.Kali Linux 2020.1修改root用户密码

    安装Kali Linux 2020.1系统后,需要使用root用户权限安装软件. 由于VMWare版本的root用户默认密码未知,所以需要在单用户模式下重新设置root用户密码.操作步骤如下: 启动K ...

  7. 【微信H5】 Redirect_uri参数错误解决方法

    1 https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx14127af0bc9fd367&redirect_uri=http ...

  8. 开发小白可以一年涨薪10w?这份java文档功不可没,学透你也可以

    靠这份文档,跳槽涨薪10K 金九银十的时候我分享了一份面试文档给我的兄弟,没想到这哥们2个月之内斩获数个BAT的offer, 最后选择了一个他最想要去的公司,既然有这么好的效果,我就打算把这份文档分享 ...

  9. Brainman(规律题)【数学思想】

    Brainman 题目链接(点击) Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 12942   Accepted: 650 ...

  10. Mac搭建Fluter应用环境

    1.创建一个路径.例如我创建是: /Users/chenghui/ 然后创建一个文件夹: development 把下载好的Fluter 解压到当前目录下: development /Users/ch ...