前置

本篇随笔包含 _.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中lang包的常用方法介绍

    JAVA API(图片来源:实验楼) 包装类 Integer包装类 方法 返回值 功能描述 byteValue() byte 以 byte 类型返回该 Integer 的值 intValue() in ...

  2. 使用Python爬取网页的相关内容(图片,文字,链接等等)

    代码解释的很详细了,有不明白的欢迎评论 ~~~滑稽 import requests from bs4 import BeautifulSoup # #获取图片 输入网址 req=requests.ge ...

  3. java中装箱和拆箱的详细使用(详解)

    一.什么是装箱?什么是拆箱? 在前面的文章中提到,Java为每种基本数据类型都提供了对应的包装器类型,至于为什么会为每种基本数据类型提供包装器类型在此不进行阐述,有兴趣的朋友可以查阅相关资料.在Jav ...

  4. java实现砝码称重

    5个砝码 用天平称重时,我们希望用尽可能少的砝码组合称出尽可能多的重量. 如果只有5个砝码,重量分别是1,3,9,27,81.则它们可以组合称出1到121之间任意整数重量(砝码允许放在左右两个盘中). ...

  5. java代码(9) ---guava之Lists、Maps

     guava之Lists.Maps 谷歌提供了guava包里面有很多的工具类,Lists和Maps集合工具,集合操作做了些优化提升 一.概述 1.静态工厂方法 (1)Guava提供了能够推断泛型的静态 ...

  6. Ansible facts详解

    Ansible是一个系列文章,我会尽量以通俗易懂.诙谐幽默的总结方式给大家呈现这些枯燥的知识点,让学习变的有趣一些. Ansible系列博文直达链接:Ansible入门系列 前言 如果你跟着前面的文章 ...

  7. java作品集:企业信息门户webtap

    作品背景 随着企业应用的软件越来越多,并且信息软件基本以B/S为主了,很多时候各种软件的地址,让大家记的头昏脑胀,并且一堆密码要记,而且大部分系统之间无法互通,虽然市面上有各种集成方案,但无法做到简单 ...

  8. 【经验心得】谈一谈我IT行业未来的方向

    随着科技的发展,越来越多的入门行业将被淘汰,其实淘汰的不仅仅是工厂.环卫工人.普工这些无技术含量的工作,有一些运维.编辑等低门槛的行业也将被淘汰,这也是我这两年看互联网发展趋势得出来的结论,人类要想发 ...

  9. @bzoj - 3711@ [PA2014]Druzyny

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 体育课上,n个小朋友排成一行(从1到n编号),老师想把他们分成若 ...

  10. @atcoder - AGC024F@ Simple Subsequence Problem

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定由若干长度 <= N 的 01 字符串组成的集合 S. ...