事件起因
查看技术文档的时候看到了数组的深度遍历,但是博主只写了一种方法,所以想着去查找更简洁的代码来实现.
于是去看了JavaScript Array的文档然后发现文档中有很多"不起眼"的API,随之注意到了Array.at(),于是乎讨论起来了Array.at()的实现方式(想着应该不会用我们的思想封装一个Len+负数实现从后面取数据的方式吧)
开始折腾
于是讨论着就去看了源码的实现方式.
// 局部代码如下
at: function at(index) {
var O = toObject(this); // 如果this不是undefined将它转成object类型
var len = lengthOfArrayLike(O); // 获取数组长度
// 获取传入的下标值 可以为字符串<但必须可以转数值的字符串才行>
var relativeIndex = toIntegerOrInfinity(index);
// 如果 传入下标值大于等于0则使用这个下标值否则使用数组长度减去这个下标值
var k = relativeIndex >= 0 ? relativeIndex : len + relativeIndex;
// 如果k越界则返回undefined否则返回该数组k下标下的值
return (k < 0 || k >= len) ? undefined : O[k];
}
// 获取数组长度
function lengthOfArrayLike (obj) {
// 将数组长度进行过滤
return toLength(obj.length);
};
// 过滤数组长度为正整数且不会越界 异常则返回0
function toLength(argument) {
// 2 ** 53 - 1 == 9007199254740991
return argument > 0 ? min(toIntegerOrInfinity(argument), 0x1FFFFFFFFFFFFF) : 0;
};
// 这个地方验证比较绕,主要目的是为了得到一个整数值
function toIntegerOrInfinity(argument) {
var ceil = Math.ceil;
var floor = Math.floor;
var number = +argument; // 防止argument为字符串将其转为数值型
// number !== number NaN!==NaN 或者 number为0 返回0
//否则大于0或小于0的小数则向0靠齐
return number !== number || number === 0 ? 0 : (number > 0 ? floor : ceil)(number);
};
得出结论
Array.at(-1) 等价于 Array[Array.length-1] 但经过简单的测试后者相对较快
<script>
// 创建一个数组填充1-99999
let arr = [];
for (let i = 0; i < 740991; i++) {
arr.push(i);
}
// 开始计时
let start = new Date().getTime();
console.log("start: ", start);
// 随机获取1000次数组元素使用at
for (let i = 0; i < 1000; i++) {
let index = Math.floor(Math.random() * arr.length);
let item = arr.at(index);
}
// 计时结束
let end = new Date().getTime();
console.log("end: ", end);
// 开始计时
start = new Date().getTime();
console.log("start: ", start);
// 随机获取1000次数组元素使用[index]
for (let i = 0; i < 1000; i++) {
let index = Math.floor(Math.random() * arr.length);
let item = arr[index];
}
// 计时结束
end = new Date().getTime();
console.log("end: ", end);
</script>
经过反复思考最后想到了Array.at()的几点好处
- 使代码变得简短整洁
- 防止有大聪明把length拼错了
- … … 欢迎补充
总结
被 number !== number 卡住后来提了个issues(丢人了一把)作者给了提示才反应过来 NaN !== NaN
Q.E.D.