背景
如果你了解Java,便知道类中未赋值的属性将在编译时由编译器赋予初始值。与Java、C#等一些静态语言不同的是,Javascript是一种解释型的动态语言,因为没有编译环节,因而它的变量类型可在程序运行时动态改变。这种弱类型的性质,也就决定了Javascript的设计中应该采用一种开放的、无意义的值作为变量的初始值——它便是undefined
。
探寻
undefined
作为Javascripts的五种基本数据类型之一,在编程中也是很常见的了。比如所有未赋值的变量都会默认为undefined
;未指明return
语句的函数也会返回undefined
;不存在的对象属性、不存在的数组项以及一些操作符等也会返回undefined
,下面我们就来一同探寻undefined
的踪迹。
变量
最常见的,未赋值的全局变量或局部变量将会返回undefined
。
var buzz;
buzz; // undefined,全局变量
(fucntion(arg) {
var fizz;
console.log(arg); // undefined,参数变量
console.log(fizz); // undefined,局部变量
})();
函数
每个函数都有返回值,如果未指定return
后的返回值,默认将返回undefined
。
var fn1 = function() {};
fn2 = function() {return;}
var res1 = fn1();
res2 = fn2();
console.log(res1); // undefined,省略return
console.log(res2); // undefined,未指定返回值
数组
访问数组中未定义数据项返回undefined
。
var arr = [1,2];
arr.length = 5;
console.log(arr[3]); // undefined
console.log(arr[10]); // undefined
对象
访问对象上的未定义属性返回undefined
。
var person = {
name:"Lee",
};
person.age; // undefined
操作符
void
操作符对后方表达式求值,不论求值结果如何,总是返回undefined
。
var res = void(1+1);
res; // undefined
陷阱
尽管undefined
的本意表示”缺少值”,本应有值,却还未定义。同时,JavaScript中的另一个基本类型变量之一null
,也有”空引用、未定义”对象之意,初学者常常将两者混为一谈,稍不留意便会跌入陷阱。
undefined使用
对于undefined
的判断,获取,转型需要牢记用法,若凭借其他语言的经验则容易发生意外结果。
判断undefined
可以使用==
、===
或typeof
操作符判断undefined
。
var buzz;
buzz == undefined; // true
buzz === undefined; // true
buzz == 'undefined'; // false
typeof buzz == undefined; // false
typeof buzz == 'undefined'; // true
当使用==
或===
时与undefined
基本类型值比较,使用typeof
时与字符串比较。这么这几种判断方法真的都安全可靠吗,我们继续下面的例子:
(function() {
var undefined = 'hello';
var buzz;
console.log(buzz == undefined); // false
console.log(buzz === undefined); // false
console.log(typeof buzz == 'undefined'); // true
})();
这是一个自调用函数,由于undefined
在Javascript中不是保留字,因而我们可以在函数内重写undefined
的值,至于原始值,只能从函数外部的全局作用域获取:
window.undefined; // 浏览器环境
GLOBAL.undefined; // Node环境
(function() {
var undefined = 'hello';
var buzz;
console.log(undefined); // 'hello'
console.log(buzz == window.undefined); // true
console.log(buzz === window.undefined); // true
console.log(typeof buzz == 'undefined'); // true
})();
总结以上结果,我们可以看到,使用typeof
来判断undefined
值,无论在什么情况下总会返回正确结果。为保障代码的健硕性,因而我们应始终使用typeof
操作符来判断undefined
。
获取 undefined
通过原始字面量获取
var buzz = 'hello';
buzz = undefined;
buzz; // undefined
通过void操作符获取
void操作符对后方表达式求值,不论求值结果如何,总是返回undefined。
var buzz = 'hello';
buzz = void 0;
typeof buzz === 'undefined'; // true
最佳实践
虽然通过原始字面量方式获取undefined
简单方便,但在【判断undefined】这一小节中,我们曾提到:undefined
不是Javascript中的保留字,其值可以在函数作用域内被改写。需要注意的是,即便是window
/GLOBAL
对象,在函数内也仍可被重写。故从window
/GLOBAL
上获取undefined
并不是100%可靠的方法。如:
(function() {
var undefined = 'hello',
foo = {},
window = {
'undefined': 'world'
};
console.log(undefined); // 'hello'
console.log(window.undefined); // 'world'
console.log(foo.a === undefined); // false
console.log(foo.a === void 0); // true
})();
于是,采用void
方式获取undefined
便成了通用准则。如underscore.js里的isUndefined
便是这么写的:
_.isUndefined = function(obj) {
return obj === void 0;
}
还有一种方式是通过函数参数缺省值。如AngularJS的源码里就用这样的方式:
(function(window, document, undefined) {
//.....
})(window, document);
“undefined
“参数通过省略传参,确保了其值是一个默认的undefined
。
undefined转型
undefined
转Number
类型返回NaN
,转String
返回字符串形式,转Boolean
返回false
。
// 显示转换
Number(undefined); // NaN
String(undefined); // 'undefined'
Boolean(undefined); // false
// 隐式转换
1 + undefined; // NaN,隐式转number
'str' + undefined; // 'strundefined',隐式转string
if(undefined) {
console.log(true); // 不会被输出
} else {
console.log(false); // false,隐式转boolean
}
null
在Java,C#等一些面向对象语言中null
代表空引用。当类中声明一个引用型变量未赋初值时,编译器会自动初始化引用值为null
。JavaScript借鉴了这一设计,也将null
定义为“空”,当一个变量值为null
时代表它未引用任何对象实体。
对于null
的典型用法是:
1. 作为函数的参数,表示该函数的参数不是对象。
2. 作为对象原型链的终点。
null
和undefined
在表现上有着一定的相似性,两者在if()
语句中,都会被自动转为false
,使用”==
“运算符两者判定相等。
function choose(param) {
if (param) {
console.log(param + ' is true');
} else {
console.log(param + ' is false');
}
}
choose(null); // undefined is false
choose(undefined); // null is false
undefined == null; // true
虽然undefined
和null
在JavaScript中都可代表“空,未定义”的意思,但他们之间还是有一些细微的区别:
null
值需要显式指定,变量赋值为null
时,代表一个对象,其引用实体为空。- 将
null
转换为数值时返回0,undefined
返回NaN
。
var foo = null;
typeof foo; // 'object'
+ null; // 0
+ undefined; // NaN
总结
- 使用
typeof
判断undefined
; - 使用
void 0
获取undefined
; undefined
与null
转型为布尔值均返回false
。