为了节省某些不想翻看冗长文章读者的时间,我把总结直接提了上来,如果想了解细节和原因,还是需要往下看的。

总结
undefined
  1. 平常我们所说的undefined是window上的一个属性,它的值是undefined。不可配置、不可枚举、不可更改。
  2. undefined不是一个关键字是JavaScript公认的设计失误之一。不是一个关键字,意味着开发人员可以定义一个名为undefined的变量,然后去更改它。
  3. 只有void 0才绝对代表变量未初始化未赋值的状态,因为undefined有可能被篡改。
  4. undefined官方的说法是一种数据类型,当声明了一个变量,却并未初始化或者赋值时,那么这个变量的类型就是Undefined,值为undefined。我觉得将undefined解释为一个变量还未初始化、未赋值的状态更为准确。这里我理解undefined用来标记变量的一种状态,而不是一个数据类型。
  5. 所以我们要避免一不能随便更改undefined的值,二不要随意给一个未初始化的变量赋值undefined。
null
  1. 与undefined相反,null就是一个关键字,不用担心null被更改的问题。
  2. null表示这个变量希望用来指向一个对象,但是现在尚未指向任何对象。表示逻辑上的对象不存在的情况。注意这里的对象不存在与对象为空{}不是一回事。
  3. 用MDN的说法就是,把null作为尚未创建的对象也许更好理解。

undefined是一个全局变量而不是一个关键字

  1. Undefined类型只有一个值那就是undefined。任何变量在没有赋值之前都是Undefined类型,值是undefined。一般我们可以使用全局变量undefined(名为undefined的变量)来表示这个值,或者使用void 0来表示。

void 运算符通常只用于获取 undefined的原始值,一般使用void(0)(等同于void 0)。在上述情况中,也可以使用全局变量undefined 来代替(假定其仍是默认值)。

  1. 上述void解释摘抄自MDN,意思是大多数情况下void 0可以使用undefined来代替。这个大多数情况就是undefined未被修改的情况下,如果undefined变量被修改了,那么undefined变量就不能用来表示变量未赋值的状态了。
一、如何证明undefined是一个全局变量。
  • 刚开始我想直接打印window,查看它的属性,结果在window上并没有找到undefined这个属性。
  • 使用Reflect.getOwnPropertyDescriptor(window,‘undefined’),我们看到window的确有undefined这个属性,但是被定义成了不可枚举,不可配置,不可更改。所以直接打印window查看它的属性找不到undefined这个属性,实际是有的,单纯的console.log打印不出来。
二、如何证明undefined可以被更改
  • 虽然window上的undefined属性无法更改,但既然undefined不是一个关键字,那么我就可以定义一个局部变量undefined,在里面去改变undefined的值。如果你在不知情的情况下,undefined被篡改,并且这时你给某个变量赋值undefined,从打印结果可以看出undefined已经不代表变量未初始化的状态了。
  • 这是JavaScript公认的设计失误之一。
  • 这也是为什么有的编程规范要求使用void 0代替undefined的原因。