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 中的实现中是没有的,这就是为什么称之为“宽松实现”的原因。
参考链接
(完)