前置

本篇随笔包含 _.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 82 删除排序链表中的重复元素 II(二)

    82. 删除排序链表中的重复元素 II 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字. 示例 1: 输入: 1->2->3->3->4- ...

  2. 如何拿到阿里P8 Offer-候选人视角谈面试

    自我介绍 首先简单自我介绍一下,我叫陈映平,花名叫做小卡,2011年校招进入腾讯,是腾讯课堂B侧的前端技术负责人.2015年响应总理的号召,跟朋友一起出来创业,跟前面一位讲师的经历有点像,然后2018 ...

  3. STL关联容器

    这里简单学习一下STL关联容器,主要是map.multimap.set.multiset以及unordered_map.前四个底层实现都是利用红黑树实现的,查找算法时间复杂度为\(O(log(n))\ ...

  4. 经典文本特征表示方法: TF-IDF

    引言 在信息检索, 文本挖掘和自然语言处理领域, IF-IDF 这个名字, 从它在 20 世纪 70 年代初被发明, 已名震江湖近半个世纪而不曾衰歇. 它表示的简单性, 应用的有效性, 使得它成为不同 ...

  5. Ubuntu一键安装Mariadb

    系统版本: debian/  ubuntu/ 添加清华大学镜像库: sudo add-apt-repository -r 'https://mirrors.tuna.tsinghua.edu.cn/m ...

  6. DBusConnection for c

    dbus的C API D-Bus 1.13.10 目录 dbus的C API Detailed Description Typedef Documentation ◆ DBusAddTimeoutFu ...

  7. nacos部署注意点

    官方Naming Configuration Service https://nacos.io/zh-cn/docs/deployment.html 划重点 单机部署 单机部署默认嵌入式存储数据 支持 ...

  8. layui 通过laytpl模板,以及laypage分页实现

    一.引用js依赖 jquery-1.11.3.min.js , layui.all.js, json2.js 二.js分页方法封装(分页使用模板laytpl) 1.模板渲染 /**  * 分页模板的渲 ...

  9. 用python做时间序列预测九:ARIMA模型简介

    本篇介绍时间序列预测常用的ARIMA模型,通过了解本篇内容,将可以使用ARIMA预测一个时间序列. 什么是ARIMA? ARIMA是'Auto Regressive Integrated Moving ...

  10. IE11下文档模式默认值是7, 而且无法更改

    IE9以上是支持css3的,但是有的IE11的浏览器里面,文档模式默认值是7,而且是无法改变的,就会导致网页布局错乱 我的IE11的文档模式默认值是11 ,如下图  (打开页面按F12) 对于默认值是 ...