本篇隨筆包含 _.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;