阅读 2218

JS中的null和undefined,undefined为啥用void 0代替?

起因

  某天,在看某位同学的js代码,代码中发现了一个奇怪的东西 void 0,虽然第一眼看不懂这是什么东西,但是根据上下文,这里应该是想判断是否等于undefined,为什么要这样写的,有什么渊源吗?顺便就把undefined和null都拿出来复习了一下.

介绍

  undefined和null是js中类型七种数据类型,这两种数据的区别是

  • undefined是声明了未定义
  • null是一个空指针,除非定义为null,否则不会出现null

null

   null是有一些奇怪的地方,例如常见的面试题

typeof null 为什么是object?

这道题目在我一开始学习js的时候就接触过,说是js设计的一个bug啦,只是因为旧代码太多,怕改正过来会造成影响,所以一直保持,也有的说这是一个空指针,空对象,所以为object.但是我总觉得这样说服力不够,于是我上网翻了一些资料

在 javascript 的最初版本中,使用的 32 位系统,并且底层都表示为2进制,为了性能考虑使用低位存储了变量的类型信息:

  • 000:对象

  • 1:整数

  • 010:浮点数

  • 100:字符串

  • 110:布尔

  • 全部为0: null

所以typeof就是利用这一机制去判断的,所以null全部为0就复合了对象的000,所以被判断为object

并且还有个注意点

null == undefined //true null和undefined用==比较结果是true,并且没有发生隐式转换,就是true
复制代码

undefined

  接下来就是undefined了,这个设计感觉也有个非常大的bug,那么重要的东西,竟然不是一个关键字,竟然是一个变量.一个变量意味着什么,你可以随意更改它啊!!

  所以有的程序员就会利用void 0去代替undefined,鬼知道原来的undefined会不会被某个阴险小人替换了.

那么void 0到底是怎么来的?

根据ECMAScript,void后面接什么都是undefined,也有的说void 0 是从其他语言带过来的习惯,是一种老司机的写法,所以下次我们要用到undefined的时候就要void 0代替,这样比较显得老司机

undefined什么情况下会被替换?

这里我自己测试了一下

  • 在谷歌浏览器69.0.3497.100版本下
    var undefined = 2;
    console.log(undefined); //undefined 
复制代码

结果是undefined,也就是在新版的谷歌浏览器里面的全局作用域下面是无法更改undefined的

    //这次改用const
    const undefined = 2; //Identifier 'undefined' has already been declared
    console.log(undefined); 
复制代码

用const则会报错,已经declared了,let也同样


  • 那就试试ie浏览器吧(IE11)
    var undefined = 2;
    console.log(undefined); //undefined 
复制代码

这样的结果还是undefined,所以在ie11的全局作用域下面也不能替换

  • 直到ie8版本的浏览器发生了变化
    var undefined = 2;
    console.log(undefined); //2
复制代码

竟然改变了,ie8的全局作用域下是可以改变undefined的

这样看来好像也没什么用是不是?ie8很多公司都不用去兼容了,慢着

  • 在谷歌浏览器69.0.3497.100版本下,我们试试在函数作用域下
(function () {
        var undefined = 2
        console.log(undefined);  //2 
    })()
复制代码

发现这样就改变了undefined

(function () {
        const undefined = 2
        console.log(undefined); //2
    })()
复制代码

const同样可行,并且在ie的11,10,9,8几个版本中,无一例外的,undefined都被覆盖了

为什么会这样呢?

  这时候想到,在全局作用域下,全局变量会变成window上面的一个属性,这时候我们查查看这个属性有什么特别不就知道原因了

console.log(Object.getOwnPropertyDescriptor(window, undefined)); //{value: undefined, writable: false, enumerable: false, configurable: false}
复制代码

这时候拿到数据属性可以看到,不可重写,不可枚举,不可改变特征值或者被删除,所以在全局作用域下面是不可以被重写的.

  那ie8呢?为什么可以?

console.log(Object.getOwnPropertyDescriptor(window, undefined)); //{configurable: false, enumerable: false, value: undefined, writable: true}
复制代码

ie8同样,不可枚举,不可删除或修改特征值,但是!!可以被重写!!所以ie8的全局作用域上面是可以被重写的!!

结论:虽然undefined在现在主流的绝大部分浏览器的全局作用域上面都是不能更改了,但是在函数作用域或者块级作用域下面还是能被重写的,当然绝大部分人应该都不会去干这种傻事,但是还是用viod 0吧,这样可以以防万一,同时也更像一个老司机的代码啊