【JS学习笔记】null与undefined

124 阅读4分钟

一、为什么JS有两个表示“无”的值

JS不同于其他语言,它有2个表示“无”的值,undefined和null。JS在设计上部分参考了Java,为什么JS需要两个值表示“无”,而Java只需要一个?

1995年JS诞生之初与Java类似,只设置了null表示“无”。但Java是静态类型语言,如果一个基本数据类型变量只声明不赋值,编译器会报错,基本数据类型必须有一个该数据类型初值(基础数据类型分配内存,存储的是当前的值),基本数据类型不会为“空”;如果声明一个引用数据类型,但是不确定值是多少可以用null表示(引用类型变量分配了内存,存放的是地址空间)。JS和Java类似数据类型分成基本类型primitive和合成类型complex(对象类型)。但是JS是动态类型语言,声明变量的时候并不会涉及类型,当前变量为空,可能是基本类型也可能是对象类型。“无”值为空对象这种设计在JS中不适用。

JS为动态类型语言,可以出现“无”值的情况有两种,一种是变量声明了但是没有赋值,不知道值是什么;另一种情况是此处的值确定就是没有。JS需要加以区分,因此需要两个表示“无”的值。

notice:此处是个人理解。

二、null与undefined的区别

null和undefined在JS中都表示“无”,他们有什么相似之处又有什么区别呢?

1.相同点

  • undefined和null在if语句中会被自动转化为false。
  • Boolean(nudefined)和Boolean(null)结果为false。
  • 都可使用可选链判空。

2.不同点

  • 定义不同

    • undefined表示“缺少值”,就是此处应该有一个值,但是还没有定义,被转化为数值是为NaN。
    • null表示“没有对象”,即此处不应该有值,被转化为数值时是0。
  • 使用场景不同

    • null的使用场景

      • 作为函数的参数,表示该函数的参数不是对象。
      • 作为对象原型链的终点。
    • undefined的使用场景

      • 变量被声明了,但没有赋值时就等于undefined。
      • 调用函数时,应该提供的参数没有提供,改参数等于undefined。
      • 对象没有赋值的属性,该属性的值为undefined。
      • 函数没有返回值时,默认返回undefined。(是异常导致的没有返回值,还是本来该函数就无返回值,并不确定)

notice:

  1. undefined==null的结果为ture,undefined===null为false。undefined是Undefined类型,null为Null类型。undefined和null值相等但是类型不同。
  2. null表明了此处无值的预期,作用类似于一个占位符。undefined表示不知道此处的值是什么,但是可能是有值的。因此JS中必须以编程的方式将一个值设置为null,但是申明一个变量不赋初值该变量就是undefined。

二、null与undefined之间的坑点

null和undefined在JS中都表示“无”,虽然我们已经知道他们的相同点和区别了,但是使用的时候还是傻傻分不清楚。每个人的编码风格也不太一样,维护的项目历史代码的写法也是千奇百怪。下面的坑你见过几个?

坑点一:判空

  • null==undefined的结果为ture,null!=undefined的结果为false。
  • null===nudefined的结果为false,null!==undefined的结果为ture。
  • typeof null=='undefined'和typeof null==='undefined'的结果为false。
    private getLineHeight = () => {
        // 有可能传入0
        if (this.props.lineHeight === undefined) {
            return 18;
        }
        return this.props.lineHeight;
    };
    render() {
        return (
            <View>
                {typeof this.props.price !== 'undefined' && (
                    <Text>this.props.price</Text>
                )}
            </View>
        );
    }
  • 易踩坑场景举例:

    • 仅仅针对为undefined或者null的场景进行判空。

坑点二:对象默认值

  • 对象结构可以指定默认值,但是如果结构的对象是null,则默认值不生效。

    const {x=3}={x:null}
    
  • 易踩坑场景举例:

    • 前端为成员变量兜底了默认值,服务端下发对象包含赋值为null的成员变量,该兜底值不会生效。
    • 工程中为某个对象的成员变量赋值为null,调用处为该成员变量设置了兜底默认值。多人开发信息不协调的场景。

坑点三:函数参数默认值

  • 如果传入函数实参是null,形参设置的默认兜底值将不生效。
    getPositiveNumbers=(numberArray: number[] = []) => {
        const positiveNumberArray = [];
        for (let i = 0; i < numberArray.length; i++) {
            if (numberArray[i] > 0) {
                positiveNumberArray.push(numberArray[i]);
            }
        }
      return positiveNumberArray;
    };
  • 易踩坑场景举例:

    • 直接透传服务端下发数据,将服务端下发的数据作为实参传递给函数,但是服务端下发的数据为null

参考文档: www.ruanyifeng.com/blog/2014/0…