参考资料
源码拷贝仓库地址(阅读的源码版本)
isLength(value)
判断传入的 value 值是否是一个有效的类数组长度值(大于 -1 小于 Number.MAX_SAFE_INTEGER 的整数)
// Number.MAX_SAFE_INTEGER
const MAX_SAFE_INTEGER = 9007199254740991
/**
* 判断传入的 value 值是否是一个有效的类数组长度值
*
* @param {*} value
* @returns {boolean}
* @example
*
* isLength(3)
* // => true
*
* isLength(Number.MIN_VALUE)
* // => false
*
* isLength(Infinity)
* // => false
*
* isLength('3')
* // => false
*/
function isLength(value) {
return typeof value === 'number' &&
value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER
}
export default isLength
isArrayLike(value)
判断 value 是否是一个类数组。如果 value 是一个类数组,value 就不是一个函数,并且有一个 length 属性,类型为 number,并且是大于 -1 小于 Number.MAX_SAFE_INTEGER 的整数
import isLength from './isLength.js'
/**
* 判断 value 是否是一个类数组。如果 value 是一个类数组,value 就不是一个函数,并且有一个 length 属性
* 类型为 number,并且是大于 -1 小于 Number.MAX_SAFE_INTEGER 的整数
*
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is array-like, else `false`.
* @example
*
* isArrayLike([1, 2, 3])
* // => true
*
* isArrayLike(document.body.children)
* // => true
*
* isArrayLike('abc')
* // => true
*
* isArrayLike(Function)
* // => false
*/
function isArrayLike(value) {
return value != null && typeof value !== 'function' && isLength(value.length)
}
export default isArrayLike
isObjectLike(value)
isObjectLike 判断 value 是否是 typeof 值为 'object' 并且 value 不为 null
/**
* isObjectLike 判断 value 是否是 typeof 值为 'object' 并且 value 不为 null
*
* @param {*} value
* @returns {boolean}
* @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
isArrayLikeObject(value)
判断 value 是否是类数组对象
import isArrayLike from './isArrayLike.js'
import isObjectLike from './isObjectLike.js'
/**
* 判断 value 是否是类数组对象
*
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an array-like object,
* else `false`.
* @example
*
* isArrayLikeObject([1, 2, 3])
* // => true
*
* isArrayLikeObject(document.body.children)
* // => true
*
* isArrayLikeObject('abc')
* // => false
*
* isArrayLikeObject(Function)
* // => false
*/
function isArrayLikeObject(value) {
return isObjectLike(value) && isArrayLike(value)
}
export default isArrayLikeObject
map(array, iteratee)
创建一个数组,数组中的元素是 iteratee 函数遍历 array 中每个元素返回的结果。
iteratee 接收三个参数 (value, index | key, array)
/**
* 创建一个数组,数组中的元素是 iteratee 函数遍历 array 中每个元素返回的结果。
* iteratee 接受三个参数 (value, index | key, array)
*
* @since 5.0.0
* @category Array
* @param {Array} array The array to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Array} Returns the new mapped array.
* @example
*
* function square(n) {
* return n * n
* }
*
* map([4, 8], square)
* // => [16, 64]
*/
function map(array, iteratee) {
let index = -1
const length = array == null ? 0 : array.length
// 创建新数组
const result = new Array(length)
while (++index < length) {
// 传入参数执行 iteratee
// 并且将结果添加到 result 中
result[index] = iteratee(array[index], index, array)
}
// 返回 result
return result
}
export default map
cancat(array, values) 以及私有依赖
isArray(value)
isArray 这个方法其实就是直接使用了 Array 的静态方法 isArray
/**
* 判断 value 是否是数组
*
* @param {*} value 要被判断是否是数组的 value
* @returns {boolean} 返回布尔值
* @example
*
* _.isArray([1, 2, 3]);
* // => true
*
* _.isArray(document.body.children);
* // => false
*
* _.isArray('abc');
* // => false
*
* _.isArray(_.noop);
* // => false
*/
const isArray = Array.isArray;
export default isArray
copyArray(source, array)
从数组 source 中将元素浅拷贝到另一个数组中
/**
* 从数组 source 中将元素浅拷贝到另一个数组中
*
* @param {Array} source 要拷贝的数组源
* @param {Array} [array=[]] 添加拷贝元素的数组,默认为空数组
* @returns {Array} 返回 array
*/
function copyArray(source, array) {
let index = -1
const length = source.length
// 如果没有传入 array,初始化一个空数组,长度和 source 长度相同
array || (array = new Array(length))
// 遍历 source ,将元素添加到 array 中
while (++index < length) {
array[index] = source[index]
}
return array
}
export default copyArray
arrayPush(array, values)
arrayPush 将一个数组中的元素添加到目标数组中(从目标数组的末端开始加入)
/**
* arrayPush 将一个数组中的元素添加到目标数组中(从目标数组的末端开始加入)
*
* @private
* @param {Array} array 目标数组
* @param {Array} values 要添加的元素组成的数组
* @returns {Array} 返回目标数组 array
*/
function arrayPush(array, values) {
var index = -1, // 初始化索引
length = values.length, // values 长度
offset = array.length; // 元素插入位置偏移量
while (++index < length) {
// 遍历 values,将元素添加到 array 中
array[offset + index] = values[index];
}
return array;
}
export default arrayPush
isArguments(value)
isArguments 判断 value 是否是 arguments 对象
import getTag from './.internal/getTag.js'
import isObjectLike from './isObjectLike.js'
/**
* isArguments 判断 value 是否是 arguments 对象
*
* @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) {
return isObjectLike(value) && getTag(value) == '[object Arguments]'
}
export default isArguments
isFlattenable(value)
isFlattenable 判断 value 是否是的 arguments 对象或者是数组,或者是可展开的对象
import isArguments from '../isArguments.js'
/** Built-in value reference. */
const spreadableSymbol = Symbol.isConcatSpreadable
/**
* isFlattenable 判断 value 是否是的 `arguments` 对象或者是数组,或者是可展开的对象
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
*/
function isFlattenable(value) {
return Array.isArray(value) || isArguments(value) ||
!!(value && value[spreadableSymbol])
}
export default isFlattenable
关于 Symbol.isConcatSpreadable,MDN 文档有详细的说明 Symbol.isConcatSpreadable
baseFlatten(array, depth, predicate, isStrict, result)
baseFlatten 将多维数组中的元素展开添加到指定的目标数组中
import isFlattenable from './isFlattenable.js'
/**
* baseFlatten 将多维数组中的元素展开添加到指定的目标数组中
*
* @param {Array} array 要被展开的数组
* @param {number} depth 展开的深度
* @param {boolean} [predicate=isFlattenable] 数组元素的校验
* @param {boolean} [isStrict] 是否严格执行 predicate 函数的校验
* @param {Array} [result=[]] 指定的添加元素的目标数组
* @returns {Array} Returns the new flattened array.
*/
function baseFlatten(array, depth, predicate, isStrict, result) {
// predicate 默认为 isFlattenable
predicate || (predicate = isFlattenable)
// result 默认为空数组
result || (result = [])
if (array == null) {
// 如果 array 不存在,返回空数组
return result
}
for (const value of array) {
// 遍历 array 数组
// 如果展开的深度大于 0 并且元素通过了 predicate 函数的校验
if (depth > 0 && predicate(value)) {
if (depth > 1) {
// 如果展开的深度大于 1,递归展开当前元素添加到 result 中
baseFlatten(value, depth - 1, predicate, isStrict, result)
} else {
// 如果展开深度为 1,将元素添加到 result 中
result.push(...value)
}
} else if (!isStrict) {
// 如果元素没有通过了 predicate 函数的校验
// isStrict 为 false,将元素添加到 result 中
result[result.length] = value
}
}
// 返回 result
return result
}
export default baseFlatten
concat(array, values)
创建一个新数组,并且将 array 和其他值添加到新数组中并返回新数组
import isArray from './isArray'
import copyArray from './.internal/copyArray'
import baseFlatten from './.internal/baseFlatten'
import arrayPush from './.internal/arrayPush'
/**
* 创建一个新数组,并且将 array 和其他值添加到新数组中并返回新数组
*
* @param {Array} array
* @param {...*} [values]
* @returns {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), // 除了 array 的所有元素集合
array = arguments[0], // array
index = length;
while (index--) {
// 除了 array 之外的所有参数添加到 args 中
args[index - 1] = arguments[index];
}
// isArray(array) ? copyArray(array) : [array] 如果 array 不是数组,将其作为元素生成数组,如果是数组,将 array 作为数据源拷贝一个新的数组
// baseFlatten(args, 1) 展开 args 元素组成新数组添加到 array 中
return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1));
}
export default concat