前置

本篇随笔包含 _.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实现指定年份月份的日历表

    输入指定的年份与月份,看这个月的日历表 package Xueying_Liu; import java.util.Scanner; public class rilibiao { public st ...

  2. Java实现旅行商问题

    1 问题描述 何为旅行商问题?按照非专业的说法,这个问题要求找出一条n个给定的城市间的最短路径,使我们在回到触发的城市之前,对每个城市都只访问一次.这样该问题就可以表述为求一个图的最短哈密顿回路的问题 ...

  3. Java实现第十届蓝桥杯人物相关性分析

    试题 H: 人物相关性分析 时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分 [问题描述] 小明正在分析一本小说中的人物相关性.他想知道在小说中 Alice 和 Bob 有多少次同 ...

  4. 实践案例丨基于ModelArts AI市场算法MobileNet_v2实现花卉分类

    概述 MobileNetsV2是基于一个流线型的架构,它使用深度可分离的卷积来构建轻量级的深层神经网,此模型基于 MobileNetV2: Inverted Residuals and Linear ...

  5. markdown分页导出pdf

    在需要分页之处,插入代码: <div STYLE="page-break-after: always;"></div>

  6. Docker+Selenium+TestNG+Maven+Jenkins环境搭建

    一.Selenium环境准备 standalone-chrome Docker容器启动: docker pull selenium/standalone-chrome version: '3' ser ...

  7. 最全的DOM事件笔记

    1. DOM事件模型 DOM是微软和网景发生"浏览器大战"时期留下的产物,后来被"W3C"进行标准化,标准化一代代升级与改进,目前已经推行至第四代,即 leve ...

  8. isinstance用法

    ''' 作用:来判断一个对象是否是一个已知的类型. 其第一个参数(object)为对象,第二个参数(type)为类型名(int...)或类型名的一个列表((int,list,float)是一个列表). ...

  9. json 拼装空list、object

    import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; public class FastJson ...

  10. GitHub 热点速览 Vol.24:程序员自我增值,优雅赚零花钱

    摘要:升职加薪,出任 CTO,迎娶白富美/高帅富,走向人生巅峰是很多人的梦想.在本期的热点速览中你将了解自由作者 Easy 如何优雅赚取零花钱的方法,以及定投改变命运 -- 让时间陪你慢慢变富.说到程 ...