• 数组中的 empty


    前言

    该篇未参考任何资料,纯个人观点,探究一下让人好奇的现象。

    正片

    最近在想,数组中的 empty 究竟是个什么样的存在呢。这不是一种类型,不能与 undefinednull 相比;又显得怪怪的,为什么 foreach() 会跳过它。于是我想试试水。

    创建一个带有 empty 元素数组最简单的方式就是使用 Array()

    const arr = new Array(3);
    
    console.log(arr); 
    // [ <3 empty items> ]
    
    • 1
    • 2
    • 3
    • 4

    现在,一步一步来看看。

    别相信值

    有时尝试着去比较了一下,像是这样:

    const arr = new Array(3);
    
    console.log(arr[0] == null); // true
    
    // 再试试绝对相等
    console.log(arr[0] === null); // false
    console.log(arr[0] === undefined); // true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    噢,原来这个值是 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    那么如何理解这个相等呢,这里问一下,如果一个对象没有 key 值,你会拿到什么?那就是 undefined

    const obj = {};
    
    console.log(obj.name); // undefined
    
    • 1
    • 2
    • 3

    所以说,这不是 empty === undefined,而是没有拿到值,然后返回一个 undefined 糊弄人呢。

    手动创建 empty

    嗯,确实有一种方式可以创建出来,虽然这并没有什么用。

    有一个操作符: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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    好像有点意思了,可以预想,用到数组身上会怎样:

    const arr = [1, 2, 3];
    console.log(arr); // [ 1, 2, 3 ]
    
    delete arr[0];
    console.log(arr); // [ <1 empty item>, 2, 3 ]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    结合普通对象一起看,就知道 empty 是什么表现了吧,那就是不存在这个字段,通过 new Array(length) 形式创建的数组就只有一个干瘪的长度而已。

    现在还有一个问题未解答。

    没有反应的 forEach()

    在前面的例子当中,演示 empty 数组使用了 forEach(),却没有任何反应。

    以前的猜想是,forEach() 应该是这样的一种实现吧:

    function forEach(arr, callback) {
    	const n = arr.length;
    	for (let i = 0; i < n; i++) {
    		callback(arr[i], i, arr);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    结合未执行的现象,可以说不可能是这样,只能说很相近,在其中还有一个判断,先看一个普通对象调用 forEach() 的表现:

    const obj = {
    	name: "obj",
    	age: 18
    };
    
    // 使用 call() 借用
    Array.prototype.forEach.call(obj, (v, i) => {
      console.log(v, i);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    表现如一,没有动静。噢,应该使用类数组对象

    const obj = {
    	0: 0,
    	1: 1,
    	length: 2
    };
    
    Array.prototype.forEach.call(obj, (v, i) => {
    	console.log(v, i);
    });
    // 0 0
    // 1 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    现在删掉一个字段如何:

    const obj = {
    	1: 1,
    	length: 2
    };
    
    Array.prototype.forEach.call(obj, (v, i) => {
    	console.log(v, i);
    });
    // 1 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    好,完善一下自己的 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这就理解了,为什么 forEach() 不会有反应,因为在执行前,判断了该字段是否存在在对象上。

    -END-

  • 相关阅读:
    C++面试常见问题 — C++语言基础
    2023届C/C++软件开发工程师校招面试常问知识点复盘Part 6
    [SwiftUI 开发] Combine使用方法
    Promise梳理
    MySQL
    Java InputStreamReader类的简介说明
    10.19作业
    【附源码】计算机毕业设计SSM食疗养生服务平台
    redis 问题解决 1
    java 前后端开发 常用下载链接
  • 原文地址:https://blog.csdn.net/qq_49661519/article/details/126809280