undefined, NaN 的真实面目

@eyasliu 2016-08-04 01:09:30发表于 eyasliu/blog

前几天发现一件有趣的事情

(function test(){
  var undefined = "this is my undefined"
  return undefined;
})() // 返回 "this is my undefined"

undefined的值居然能被重写!

接下来再试了一下 null NaN,发现NaN也能被重写

原因

  • undefined 属于Undefined类型唯一的值,是js基础数据类型之一
  • null 属于 Object 类型,代表空对象

其实它们本质上,就是一个变量名罢了,很普通的一个变量名。既然是变量名,那么给他重新赋值试试看

undefined = 'Hello!';
window.undefined = 'Hi!';
alert(undefined) // 弹出 undefined

重新赋值的时候,不会报错,但是结果是改不了的,而且这种方式的赋值,是属于全局变量的赋值。这个看到这个行为,我立马想起了 Object.defineProperty,于是,用它去修改undefined变量的写入属性试试

Object.defineProperty(window, 'undefined', {
    writable: true
})
// throw error: Uncaught TypeError: Cannot redefine property: undefined(…)

不给重新定义 undefined 的属性。好吧,到了这一步,我已经明白了 undefined 的猫腻了。

总结

undefined 的确就是一个全局变量,值就是 undefined,只不过这个全局变量在js内部规定了不能更改它的属性。但是在局部作用域中原本是没有undefined这个变量,可以使用var关键字去声明这个变量,新声明的undefined跟全局哪个undefined没有任何关系,当然就可以正常赋值了。

究其原因,还是因为 undefined 不是js的关键字导致的

解决方案

undefined 和 NaN 变量能够被更改,那就会导致不安全的可能性,那么如何保证使用的undefined一定是真正的哪个undefined呢,而不是被重写之后的undefined。这里有几种方案

  • 永远不要声明 undefined 这个变量名,因为变量在使用的时候,如果不声明,都会去使用全局变量,而全局变量那个undefined一定是正确的
  • 使用局部作用域时,多加一个参数
(function(p1, p2){
    // 传参时因为undefined变量没有传进来,所以自动设置为undefined
    alert(undefined);
})(val1, val2, undefined)
  • 使用替代表达式
// undefined 可以使用 void(0) 代替
undefined = void(0)
// NaN 可以使用 0/0 代替
NaN = 0/0