by @zhangbao(zhangbao) #0105
概览
什么是类数组呢?查看 Lodash _.isArrayLike(value) 函数的实现,得知参数 value 须符合下列条件:
- 不是函数
- 有
length属性 - 且
length属性值是不大于Number.MAX_SAFE_INTEGER的自然数
字符串就符合这个条件,说明它就是类数组。

Lodash 的实现
著名 JS 工具库 Lodash 提供了一个工具函数:_.isArrayLike(value),检查某个值是否为类数组的。下面是官方给的用例:
_.isArrayLike([1, 2, 3]);
// => true
_.isArrayLike(document.body.children);
// => true
_.isArrayLike('abc');
// => true
_.isArrayLike(_.noop);
// => false
_.isArrayLike 的实现细节
isArrayLike
下面是定义函数 isArrayLike 的地方:
import isLength from './isLength.js'
function isArrayLike(value) {
return value != null && typeof value !== 'function' && isLength(value.length)
}
首先检查输入的值:
value != null:这个判断使用的是!=,而非!==。令判断结果为false的值有两个:null和undefined。就是说,如果向isArrayLike函数传入的值是null或undefined,那么第一个判断都未满足,直接返回false。
💡 提示: 这里引入了 JS 一个小怪癖的地方,就是规范中定义对于抽象相等算法(
==内部执行的就是此算法):null == undefined比较结果返回true,自然null != undefined的返回结果为false。
typeof value !== 'function':传入值不能是函数,如果函数的话,也不算是类数组。isLength(value.length):最后检查传入值的length属性,isLength(value.length)返回值即isArrayLike的返回值。
isLength
isLength 函数是用来干什么的?我们来看下:
const MAX_SAFE_INTEGER = 9007199254740991
/**
* Checks if `value` is a valid array-like length.
*
* **Note:** This method is loosely based on
* [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
*
* ...
*
*/
function isLength(value) {
return typeof value === 'number' &&
value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER
}
根据注释,我们知道 isLength 函数是用来检查传入值 value 是否为有效长度。这里的 MAX_SAFE_INTEGER 就等于 Number.MAX_SAFE_INTEGER 的值,这样写的目的估计是为了效率,能少一步计算。
根据判断逻辑,我们知道所谓“有效的长度值”,是指值不大于 Number.MAX_SAFE_INTEGER 的自然数。
比如以下这些值,就不能算是有效的长度值:
isLength(Number.MIN_VALUE)
// => false。负数不是
isLength(Infinity)
// => false。无穷大不是
isLength('3')
// => false。字符串也不是
额外说明
根据 isLength 方法的注释说明:此种验证方式是对规范中定义的抽象算法 ToLength 的宽松实现。下面是规范中的定义:

相较于规范中的定义,后者是包含类型转换和参数值纠正逻辑的:
- 类型转换:首先将参数转为整数(
ToInteger(argument))
2. 参数纠正:负值转为+0;无穷大转为 253 - 1 等。
而这在 Lodash 中的实现中是没有的,这就是为什么称之为“宽松实现”的原因。
参考链接
(完)