本篇随笔包含 _.compact
和 _.concat
及其依赖的工具函数。javascript
你可能须要一些 JavaScript 基础知识才能看懂一些没有注释的细节。java
_.compact(array)
建立一个新数组,包含原数组中全部的非假值元素。例如 false
, null
, 0
, ""
, undefined
, 和 NaN
都是被认为是“假值”。segmentfault
/** * 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
/** * 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; }
检查 value
是不是类对象。若是一个值不是 null
,而且 typeof
结果为 object
,则该值为类对象。app
/** * 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
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
检查 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
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
/** * 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
/** * 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(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;