该篇未参考任何资料,纯个人观点,探究一下让人好奇的现象。
最近在想,数组中的 empty
究竟是个什么样的存在呢。这不是一种类型,不能与 undefined
和 null
相比;又显得怪怪的,为什么 foreach()
会跳过它。于是我想试试水。
创建一个带有 empty
元素数组最简单的方式就是使用 Array()
:
const arr = new Array(3);
console.log(arr);
// [ <3 empty items> ]
现在,一步一步来看看。
有时尝试着去比较了一下,像是这样:
const arr = new Array(3);
console.log(arr[0] == null); // true
// 再试试绝对相等
console.log(arr[0] === null); // false
console.log(arr[0] === undefined); // true
噢,原来这个值是 empty === undefined
呀。错了,看一个对比的例子:
const arr1 = new Array(3);
// 没动静??
arr1.forEach((item) => console.log(item));
// 字面量形式创建一个 `undefined` 数组
const arr2 = [undefined, undefined, undefined];
arr2.forEach((item) => console.log(item));
// undefined
// undefined
// undefined
那么如何理解这个相等呢,这里问一下,如果一个对象没有 key
值,你会拿到什么?那就是 undefined
。
const obj = {};
console.log(obj.name); // undefined
所以说,这不是 empty === undefined
,而是没有拿到值,然后返回一个 undefined
糊弄人呢。
嗯,确实有一种方式可以创建出来,虽然这并没有什么用。
有一个操作符:delete
。可以用于删除对象的值,或者说,可以删除一个字段。
const obj = {
name: "obj"
};
console.log(obj); // { name: 'obj' }
console.log(obj.name); // obj
delete obj.name;
console.log(obj); // {}
console.log(obj.name); // undefined
好像有点意思了,可以预想,用到数组身上会怎样:
const arr = [1, 2, 3];
console.log(arr); // [ 1, 2, 3 ]
delete arr[0];
console.log(arr); // [ <1 empty item>, 2, 3 ]
结合普通对象一起看,就知道 empty
是什么表现了吧,那就是不存在这个字段,通过 new Array(length)
形式创建的数组就只有一个干瘪的长度而已。
现在还有一个问题未解答。
在前面的例子当中,演示 empty
数组使用了 forEach()
,却没有任何反应。
以前的猜想是,forEach()
应该是这样的一种实现吧:
function forEach(arr, callback) {
const n = arr.length;
for (let i = 0; i < n; i++) {
callback(arr[i], i, arr);
}
}
结合未执行的现象,可以说不可能是这样,只能说很相近,在其中还有一个判断,先看一个普通对象调用 forEach()
的表现:
const obj = {
name: "obj",
age: 18
};
// 使用 call() 借用
Array.prototype.forEach.call(obj, (v, i) => {
console.log(v, i);
});
表现如一,没有动静。噢,应该使用类数组对象:
const obj = {
0: 0,
1: 1,
length: 2
};
Array.prototype.forEach.call(obj, (v, i) => {
console.log(v, i);
});
// 0 0
// 1 1
现在删掉一个字段如何:
const obj = {
1: 1,
length: 2
};
Array.prototype.forEach.call(obj, (v, i) => {
console.log(v, i);
});
// 1 1
好,完善一下自己的 forEach()
,并且跟进测试:
function forEach(arr, callback) {
const n = arr.length;
for (let i = 0; i < n; i++) {
if (i in arr) {
callback(arr[i], i, arr);
}
}
}
const obj = {
1: 1,
length: 2
};
forEach(obj, (v, i) => {
console.log(v, i);
});
// 1 1
这就理解了,为什么 forEach()
不会有反应,因为在执行前,判断了该字段是否存在在对象上。
-END-