凡事靡不有初,鲜克有终。既然开始写博客了,就一直写下去。
JavaScript有两个“空值”用来表示信息缺失,undefined和null。
- undefined表示“没有值”(既不是原始值也不是对象)。访问未初始化的变量、缺失的参数,以及缺失的属性会返回这个空值。并且如果函数中没有任何显示的返回值时,会隐式地返回undefined。
- null的意思是“没有对象”。为何要如此为难程序员,偏偏要戳我们的痛处。~_~在用到对象的时候它表示空值(比如参数、对象链中的最后一个元素等)。
undefined和null是仅有的在访问任何属性抛出异常时都会得到的值。
1 > function returnFoo(x) { 2 return x.foo; 3 } 4 > returnFoo(true) 5 undefined 6 > returnFoo(0) 7 undefined 8 9 > returnFoo(null) 10 Uncaught TypeError: Cannot read property 'foo' of null 11 > returnFoo(undefined) 12 Uncaught TypeError: Cannot read property 'foo' of undefined
undefined更多的时候是表示不存在的元数据。相反的,null表示空值。例如,访问一个JSON节点时返回值的意义如下:
- undefined表示删除一个对象属性或数组元素。
- null表示将属性或者元素设置为空。
一、undefined和null的出现场景
回顾一下undefined和null出现的各种场景。
1. undefined出现的场景:
- 未初始化的变量是undefined
1 > var foo; 2 > foo 3 undefined
- 缺失的参数是undefined
1 function f(x) { return x }; 2 > f() 3 undefined
- 如果访问一个不存在的属性,会返回undefined
1 var obj = {};//empty object 2 > obj.foo 3 // undefined
- 如果函数中没有显示地返回任何值,函数会隐式返回undefined
function f() {}; > f() //undefined
function g() { return; }; > g() //undefined
2. null的出现场景
- null是原型链最顶端的元素
1 > Object.getPrototypeOf(Object.prototype) 2 < null
- 当字符串中没有匹配到正则表达式的结果时,RegExp.prototype.exec()会返回null
1 < /x/.exec('aaa') 2 > null
二、 检测判断undefined和null
- 检测null
if (x === null) ...
- 检测undefined,通过严格相等(===)检测undefined,它是一种规范的检测方法
if (x === undefined) ...
你也可以通过typeof运算符检测undefined,但是最好使用上面提到的方法。
- 检测undefined或null,大多数函数允许使用undefined或null来表示缺省值。有一种显式的比较方式来检测它们。
// Does x have a value? if (x !== undefined && x !== null) { ... } // Is x a non-value? if (x === undefined || x === null) { ... }
另一种检测方式是利用undefined和null都可被认为是false的特性:
// Does x have a value (is it truthy) ? if (x) { ... } // Is x false? if (!x) { ... } //注意:false,0,NaN和''也可以被认为是false
console.log('' == false)
VM698:1 true
三、undefined和null的历史
undefined和null两者都可以作为一个简单的空值,为什么JavaScript有两个这样的值呢?这是有历史原因的。
JavaScript采用了Java中将变量分为原始值和对象的处理方式。同时也使用Java中表示“非对象”的值null。遵循C语言的先例,null在强制转换数字时会变为0(Java不会这样)。
1 Number(null) 2 //0 3 5 + null 4 //5
值得注意的是,JavaScript的第一个版本没有异常处理。因此,在遇到未初始化的变量和缺失的参数等异常情况时需要通过一个值来表示。null是个很好的选择,但是Brendan Eich想要在这个时候避免两种情况。
- 这个值不应该具有指向性,因为它表达的不仅仅是一个对象。
- 这个值的强制转换不应该为0,因为这会使错误难以发现。
因此,Eich将undefined作为另外一个空值加进了JavaScript。它会强制转换为NaN:
Number(undefined) //NaN 5 + undefined //NaN
四、修改undefined
undefined是全局对象的一个属性(同时也是一个全局变量)。在ECMAScript 3中,看到undefined时需要特别注意,因为很轻易地就会改变它的值。在ECMAScript 5中就没必要,因为undefined是只读的。
有两种很流行的技巧可以用来防止改变undefined(它们对于老的JavaScript引擎还是很有意义的):
(1)技巧一
隐藏全局undefined(因为它可能是错误的值)。
(function (undefined) { if (x === undefined) ... // safe now }()); // don't hand in a parameter
在上面的代码中,undefined保证会是正确的值,因为它的值不是由函数调用时所提供的。
(2)技巧二
和'void 0'进行比较,'void 0'总是undefined
if (x === void 0) // always safe