在《变量量和数据类型》系列列的第⼀一个章节中,我们主要针对 JavaScript 中原始类型和引⽤用类型两⼤大数据 类型之间的一些区别做了讲解。从这⼀一章节开始,我们就要开始对两大数据类型中的各种小数据类型来 做具体的分析了了。
噔 —— 噔—— 噔—— 噔——!
今天我们的主⻆角就是原始数据类型中的 null 和 undefined 两个特殊的数据类型。
分不不清的 null 和 undefined 在⼤多数的计算机语⾔言,都是有且仅有一个值⽤用来表示「⽆」。例如 C 语⾔的 NULL 、Java 语言的
null 、Python 语言的 None 、Ruby 语言的 nil 。
但奇怪的是,JavaScript 语⾔却有两个值⽤用来表示「无」: null 和 undefined 。这是为什么呢?
相似性
在 JavaScript 中,将一个变量赋值为 undefined 或 null ,⽼老老实说,⼏几乎没区别。
var a = undefined;
var a = null;
上⾯面代码中,变量a 被依次赋值为 undefined 和 null ,而这两种写法⼏乎是等价的。
undefined 和 null 在 if 语句中,都会被⾃自动转为 false ,相等运算符甚至直接报告两者相等。
if (!undefined)
console.log('undefined is false');
// undefined is false
if (!null)
console.log('null is false');
// null is false
undefined == null
// true
上⾯面代码说明,两者的行为是辣么的相似!
既然 undefined 和 null 的含义与用法都差不多,为什么要同时设置两个这样的值,这不是无端增加 JavaScript 的复杂度,令初学者困扰吗?Google 公司开发的 JavaScript 语⾔的替代品 Dart 语⾔言,就明确 规定只有 null ,没有 undefined 。
历史原因
《Speaking JavaScript》书中解释了了为什么 JavaScript 语言中有两个值都表示「无」,这其中是与 JavaScript 的历史有关的。
1995 年 JavaScript 诞生时,它也像 Java 一样,只设置了 null 用来表示「无」的值。又根据 C 语⾔言的 传统,将 null 设计成可以自动转换为 0。
但是,JavaScript 的设计者 Brendan Eich 觉得这样做还不够,原因有两个:
首先,JavaScript 中的 null 同 Java 中的 null 一样,被当作一个对象。但是,JavaScript 中的数据类 型分成了了原始类型(primitive)和复合类型(complex)两⼤大类。 Brendan Eich 觉得,用来表示「无」 的值最好不是对象。
其次,JavaScript 的最初版本没有包括错误机制处理,发生数据类型不匹配时,往往是自动转换类型或 者默默的失败。 Brendan Eich 觉得,如果 null 自动转为 0,那么很多错误都不容易发现了了。
因此, Brendan Eich 又设计一个 undefined 。 初始设计在 JavaScript 最初的版本中,是这样去区分 null 和 undefined 的:
null 表示一个「无」的对象,转为数值时为 0;
undefined 表示一个「⽆无」的原始值,转为数值时为 NaN ;
Number(null); // 0
null + 5; // 5
Number(undefined)
// NaN
5 + undefined
// NaN
目前的用法像上面那样的区分方式,在实践中很快就被证明不可⾏。
目前, null 和 undefined 基本是同义的,只有一些细微的差别:
null 表示「没有对象」,即此处不应该有值。典型的⽤用法是: 作为函数的参数,表示该函数的参数不是对象;
作为对象原型链的终点;
undefined 表示「缺少值」,即此处应该有值,但还没定义。典型的⽤用法是:变量量声明后还未赋值时,值为 undefined ; 调⽤函数时,没有提供形参所对应的实参,形参值为 undefined ; 对象的属性未赋值时,属性值为 undefined ; 函数没有设置返回值时,默认返回值为 undefined ;
Object.getPrototypeOf(Object.prototype)
// null
var i;
i // undefined
function f(x){console.log(x)}
f() // undefined
var o = new Object();
o.p // undefined
var x = f();
x // undefined
结束语
JavaScript 中同时存在 null 和 undefined 是合理的。
因为 JavaScript 是一⻔门动态类型语⾔,成员除了了表示存在的空值外,还有可能根本就不存在(因为存不 存在只在运⾏期才知道),所以这时就需要一个值来表示对某成员的 getter 是取不到值的,这也就是undefined 的意义所在。而对于 Java 这种静态类型语言,如果有 undefined 这种情况,就会直接编译失败,因此它不需要一个这样的类型,所以只用 null 来表示语义上的空值即可。
前⽂提到的 Dart 中也不存在 undefined ,最大原因恐怕也是因为 Dart 像 Java 一样是一个静态类型语 言(或者说是一个有编译期静态类型检查的语言,在运行期并不进行类型检查),所以不需要设⽴一个undefined 这样的类型。
(温馨小提示:Google 公司推出的跨平台的移动端开发框架 Flutter 就是采用的 Dart 语⾔言,所以提醒各 位前端程序员们,要开始学习新东西了哦~)
学习更多IT知识“朗沃IT学习”