大多数计算机语言,有且仅有一个表示"无"的值,比如,C语言的NULL,Java语言的null,Python语言的None,Ruby语言的nil。
有点奇怪的是,JavaScript语言居然有两个表示"无"的值:undefined和null。这是为什么?
一、相似性
在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的历史有关。1995年JavaScript诞生时,最初像Java一样,只设置了null作为表示"无"的值。
根据C语言的传统,null被设计成可以自动转为0。
Number(null) // 0 5 + null // 5
但是,JavaScript的设计者Brendan Eich,觉得这样做还不够,有两个原因。
首先,null像在Java里一样,被当成一个对象。但是,JavaScript的数据类型分成原始类型(primitive)和合成类型(complex)两大类,Brendan Eich觉得表示"无"的值最好不是对象。
其次,JavaScript的最初版本没有包括错误处理机制,发生数据类型不匹配时,往往是自动转换类型或者默默地失败。Brendan Eich觉得,如果null自动转为0,很不容易发现错误。
因此,Brendan Eich又设计了一个undefined。
三、最初设计
JavaScript的最初版本是这样区分的:null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。
Number(undefined) // NaN 5 + undefined // NaN
四、目前的用法
但是,上面这样的区分,在实践中很快就被证明不可行。目前,null和undefined基本是同义的,只有一些细微的差别。
null表示"没有对象",即该处不应该有值。典型用法是:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
Object.getPrototypeOf(Object.prototype) // null
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
var i; i // undefined function f(x){console.log(x)} f() // undefined var o = new Object(); o.p // undefined var x = f(); x // undefined
(完)
陈玉鸣 说:
很好的两条结论:
null表示"没有对象",即该处不应该有值。
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。
2014年3月28日 12:55 | # | 引用
Sunaiwen 说:
这两个东西的资料总是看了又看,无耐总是记不住啊。看来用的还是太少?
2014年3月28日 20:51 | # | 引用
ae86108 说:
个人觉得还是根据语义来区分吧,null更多的表示引用语义而undefined更多的表示值语义,虽然在数值上接近。
最近在看郑辉老师的书,讲编程范式和OOP思想,觉得获益匪浅,对各种语言也有了更深刻的认识,接下来要做的就是多接触体会了。
阮老师的博文我也很喜欢的说,讲的很通俗易懂,更多的细节可以自己去研究,很符合奥卡姆剃刀原则:)
2014年3月29日 13:20 | # | 引用
RedNax 说:
虽然一开始我觉得就null和undefined写一篇文章太大惊小怪了,不过考虑了一下其实蛮多东西值得挖掘的:
1.null 和 undefined在现代JS语义里面是有明确区别的:
null 表示一个值被定义了,定义为“空值”;
undefined 表示根本不存在定义。
所以设置一个值为 null 是合理的,如
objA.valueA = null;
但设置一个值为 undefined 是不合理的,如
objA.valueA = undefined; // 应该直接使用 delete objA.valueA; 任何一个存在引用的变量值为undefined都是一件错误的事情。
这样判断一个值是否存在,就可以用
objA.valueA === undefined // 不应使用 null 因为 undefined == null,而 null 表示该值定义为空值。
这个语义在JSON规范中被强化,这个标准中不存在 undefined 这个类型,但存在表示空值的 null 。在一些使用广泛的库(比如jQuery)中的深度拷贝函数会忽略 undefined 而不会忽略 null ,也是针对这个语义的理解。
2. JS 中同时存在 undefined 和 null 是合理的。
首先在 Java 中不存在 undefined 是很合理的:Java 是一个静态类型语言,对于 Java 来说不可能存在一个“不存在”的成员(不存在的话直接就编译失败了),所以只用 null 来表示语义上的空值。而 JavaScript 是一门动态类型语言,成员除了表示存在的空值外,还有可能根本就不存在(因为存不存在只在运行期才知道),所以这就要一个值来表示对某成员的 getter 是取不到值的。
至于 dart 不存在 null, 最大原因恐怕是 dart 像 java 一样是一个静态类型语言(或者说是一个有编译期静态类型检查的语言,在运行期并不进行类型检查),所以可以不需要设立一个 undefined 这样的类型。
虽然这两个东西的区别确实会令初学者困扰,但掌握并理解这两个值的语义实际上和理解 prototype/scope 一样是非常重要的。
(什么?留言不能超1200字?)
2014年3月30日 01:06 | # | 引用
RedNax 说:
(续)
3. typeof null 结果是 ”object“ 更像是一个设计失误
因为 typeof null === "object" 而认为 null 语义是表示空对象是个不谨慎的猜测,感觉像是先射箭后画靶一般。简单的反例:在强类型数据交换协议 odata(http://www.odata.org/)的 JSON 格式中,即使一个成员定义为特定类型(比如string),也可以设置其值为 null 来表示这个值是空值,这可不是表示这个成员是空对象,只是说值为空而已(和空字符串、0、false有所区别)。
而 typeof null === "object" 更可能是一个设计失误,所以在 harmony 中有提议将这个返回值修正为 null :
http://wiki.ecmascript.org/doku.php?id=harmony:typeof_null
当然该提议因为会造成大量旧 Javascript 脚本出现问题而被否决了……
2014年3月30日 01:06 | # | 引用
阮一峰 说:
谢谢说明,觉得比我说得清楚,确实如此。
2014年3月30日 11:10 | # | 引用
wjp 说:
var dom = document.getElementById('domId');
如果domId不存在,dom变量也为null,这也是常用的一种案例。
2014年3月30日 13:00 | # | 引用
latpaw 说:
dart不存在undefined,手误吧
2014年3月31日 09:40 | # | 引用
Tonni 说:
非常好的文章!
2014年3月31日 13:23 | # | 引用
芝麻飞来 说:
undefined和null就这么理解就可以:null是声明了但没有初始化,undefined是没有初始化。
2014年3月31日 14:53 | # | 引用
RedNax 说:
说得对,我本来是想说dart不存在undefined……
2014年3月31日 15:49 | # | 引用
Siuis 说:
虽然有区别,但是Scala的None、Null、Nil、Nothing、Unit猛的一看简直要逆天......
2014年4月 1日 18:48 | # | 引用
KeenWon 说:
对于javascript
undefined: 代表一切未知的事物,啥都没有,无法想象,代码也就更无法去处理了。
null: 有那么一个概念,但没有东西。无中似有,有中还无。虽难以想象,但已经可以用代码来处理了。
2014年4月 1日 21:07 | # | 引用
琅琊 说:
“undefined值是派生自null值”这个句话又怎么理解呢?老师!
2014年4月 2日 23:06 | # | 引用
linkarys 说:
峰哥,想换工作了,去上海跟你混吧
2014年4月 4日 11:04 | # | 引用
林 说:
指正一个错误 python里面的‘无’不是none 而是None
2014年4月 4日 11:20 | # | 引用
小谈 说:
写程序就是要弄清楚原理
2014年4月 4日 17:39 | # | 引用
vivi单 说:
感谢这么多年的辛勤努力,让我们读到了这么多的好文章。
2014年4月 6日 01:10 | # | 引用
斌瑞 说:
undefined 更多的时候指向一种错误。
2014年4月 8日 11:01 | # | 引用
李鹏程 说:
阮老师好,我是一名刚接触前端的学生,对JavaScript特别感兴趣的,看您不是学经济的,怎么对编程这么懂啊?而且看您写的文章总是受益匪浅,能学到好多不同新鲜的知识,您是怎么做到的呢,求老师指点迷津。
2014年4月 8日 16:14 | # | 引用
shadyxu 说:
python的是None,不是none。
2014年4月18日 19:29 | # | 引用
阮一峰 说:
已经改正,谢谢指出。
2014年4月19日 07:54 | # | 引用
王小黑 说:
仅以个人观点看 先生做事做人很认真 我会继续关注你
很有意思 很有趣 也很有帮助
2014年4月19日 20:30 | # | 引用
黄俊悫 说:
写的很好。博客很漂亮,不错。
2014年4月21日 20:42 | # | 引用
虚谷 说:
平时一直用null, 但有一次忘记写什么功能了,null就不起作用,查了好多资料,最后换成undefined就好了。
2014年5月 8日 17:27 | # | 引用
s79 说:
可能是:
window.onbeforeunload = function() {
return $body.hasClass('playing') ? '游戏仍在进行中!' : undefined;
};
IE 需要返回 undefined 才不会弹出提示。
2014年5月13日 04:09 | # | 引用
yuhai 说:
“我觉得这个网站应该有个专业团队来管理,找了半天结果是undefined。后来阮先生说这个网站不需要专业团队来管理,结果就是null了。”
2014年5月19日 13:35 | # | 引用
lxjwlt 说:
哭了 阿里面试就问到这一题 答不上
2014年6月14日 17:37 | # | 引用
krazymoon 说:
"null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN"
但是 parseInt和parseLong不这么认为:
parseInt(null) 和 parseFload(undefined) 返回都是 NaN
2014年6月30日 16:20 | # | 引用
Solid 说:
如果null表示“此处不应有值”,那么Dom中的onxxxx事件,在未定义的时候默认是null,怎么理解?
2014年7月 1日 19:14 | # | 引用
我土鳖我自豪 说:
若你尝试对某元素引用一个该元素并不支持的事件,你会发现该元素的'on事件名'属性是undefined。但如果某事件被该元素所支持,但事件处理函数没设置,那么'on事件名'是null。
2014年7月 6日 20:47 | # | 引用
简单的程序员 说:
null
Q:有张三这个人么?
A:有!
Q:张三有房子么?
A:没有!
undefined
Q:有张三这个人么?
A:没有!
2014年7月16日 23:04 | # | 引用
victor 说:
我觉得这个转换是合理的,NaN 表示的是一个"不是数字的数字", 包括了所有不是数字的东西(并集),也就包括 null, undefined, "abc" ....
2014年7月17日 10:35 | # | 引用
jaka 说:
我的理解:
null是js语言的关键字;
undefined有几个意思:
1.undefined值本身,比如没有赋值的局部变量默认值就是undefined;
2.作为运行环境中全局变量的一个属性(浏览器环境中就是有window下有个undefined属性);
3.Undefined类型
参考:http://modernweb.com/2013/12/09/exploring-the-abyss-of-null-and-undefined-in-javascript/
2014年7月18日 16:11 | # | 引用
王林 说:
undefined 应该是没有声明吧,无所谓初始化
2014年9月30日 10:15 | # | 引用
hebe 说:
null针对的是对象,表示一个未分配内存指针的对象,undefined针对原始类型,就是变量存放值的那个盒子里是空的
2014年10月28日 17:22 | # | 引用
工程师 说:
这样说可能更好理解:
undefined 是期房 X小区X栋X单元,房子没建呢,更别说住人了,开发商也可能卷款跑路,房子也可能烂尾
null 是待售现房,有房子了,暂时还没人住,不管以后有没有人住,至少房子在那里
你找X小区X栋X单元的业主,如果房子还没建,那就是undefine;如果建了没卖,就是null
2014年10月28日 19:53 | # | 引用
lwh 说:
null 部分改成
Q:有张三这个人么?
A:有!
Q:张三在哪?
A:已去世了
效果更好些
2015年1月 9日 07:07 | # | 引用
花瓣奶牛 说:
@RedNax:
好厉害,有博客吗?我想去看看
2015年1月17日 14:21 | # | 引用
龙 说:
根据js的规范,null不属于object。但是用表现来看,null的typeof又是object。设计很糟。
2015年3月 6日 07:46 | # | 引用
cunshuifengyun 说:
这个确实比阮老师的更明确一些,阮老师的博文已经看了很多篇了,非常喜欢其页面布局,给人一种清新自然的感觉,没有一点看教科书的疲惫感。其对javascript的某些方法思想方面的讲解让人能够很容易理解,可是其对于一些基本术语的描述就没有权威书籍讲解得正确了,如果抱着纯接收式的心态来阅读,就很容易走偏。
2015年6月10日 11:47 | # | 引用
大青山 说:
其实我觉得这个样子理解是不是要好些:
js在运行前还有一个 预加载 预加载的目的是 要事先构造运行环境例如全局环境,函数运行环境,还要构造作用域链,而环境和作用域的构造的核心内容就是 指定好变量属于哪个范畴,因此在javascript语言里变量的定义是在预加载完成而非在运行时期。
那么问题来了: 在运行期,就会发生赋值行为等等,没有发生赋值行为的默认就会把它设置为undefined,所以这里可以这样理解null和undefined的区别在于有没有发生赋值行为
2015年6月19日 10:29 | # | 引用
xhay 说:
总结的很好,学习了。。博主的文章很值得看
2015年6月29日 11:44 | # | 引用
rambo 说:
null 据说还有一个用法。大神分析一下
将一个变量设置为null。 意味着这个变量不用了。 这个时候gc会把它立即回收!
2015年7月18日 16:14 | # | 引用
wzysoft 说:
如果null表示有定义,并且定义值为空;
undefined表示根本就不存在定义;
测试: var x;
console(x);//undefined
console(y);//报错 y is not defined
如果按上面两句的理解,console(x)应该不晓得是打印个什么出来; console(y)不应该是打印undefined吗?因为y是没定义的,x是被定义了但是没有初始化;
2015年10月29日 17:30 | # | 引用
wzysoft 说:
通过对你这两句话的理解,下面的语句打印结果如下:var x; console.log(x);//? console.log(y)//undefined
但是实际是console.log(x);//undefined console.log(y)//y is not defined
虽然一开始我觉得就null和undefined写一篇文章太大惊小怪了,不过考虑了一下其实蛮多东西值得挖掘的:
1.null 和 undefined在现代JS语义里面是有明确区别的:
null 表示一个值被定义了,定义为“空值”;
undefined 表示根本不存在定义。
2015年10月29日 17:37 | # | 引用
yangtze 说:
可以再补充一个: NaN(Not a Number)
2015年12月17日 21:58 | # | 引用
simon.xi 说:
@RedNax:
大赞一下,讲的很好,从语义上来做区分。
2016年1月26日 13:24 | # | 引用
vijay 说:
“undefined值是派生自null值”这句话的派生又怎么理解呢?
2016年2月22日 20:58 | # | 引用
假日企鹅 说:
null和undefined在内存中有什么区别?
2016年4月27日 11:31 | # | 引用
xgqfrms 说:
var a;
if(a==undefined) alert('undefined');//true
if(a==null) alert('null');//true
if(null==NaN) alert('NaN=null');//undefined
if(undefined==NaN) alert('NaN=undefined');//undefined
if(NaN) alert('NaN');//undefined
var a=null;//(0/false)
var b=undefined;//(false)
var c = 7 ;
alert('undefined+null='+(a+b));//NaN
alert('c+null='+(a+c));//7
alert('c+undefined='+(b+c));//NaN
chrome 测试结果!
个人认为:
null 的取值是(0/false),
undefined 的取值是(false/NaN)。
2016年8月13日 23:05 | # | 引用
zhbhun 说:
感觉 null 和 undefined 在实际开发中容易混淆,增加了编程负担。例如,经常要判断某个变量是否非 undefined 和 null,还需要这么写 typeof v !== 'undefined && null !== null。还有,ES6 对象解构时,只有 undefined 的属性才支持默认值,结合本文来看,null 应该是代表一个特殊的值(空值),这个在实际开发中区别对待是否有意义 —— 我在大部分的代码中都是要给 null 和 undefined 写个默认值的。除了文中提到的历史原因外,是否都是把 null 和 undefined 当成其他语言的 null/None 来处理,有哪些场景是需要区别对待的?
2016年9月19日 16:53 | # | 引用
zhbhun 说:
真的需要 undefined 吗?假设 JS 没有 undefined 的话,会怎样?
1. 变量声明,初始化值为 null
2. 调用函数,参数默认值为 null
3. 对象没有赋值的属性,默认为 null
4. 函数没有返回值,默认返回 undefined
不考虑历史问题,除了第三点导致无法区分对象是存在属性外,其他几点会还会带来什么样的问题?
对于第三点,完全可以通过另外的接口来判断该对象是否存在该属性,这有点类似于 Java 的 Map,不存在的 key 也是返回 null。而且,JS 本身也是有接口判断对象是否存在某个属性的。
上面给自己提了好几个问题,实在是搞不懂,希望大家帮忙指导!
2016年9月19日 17:15 | # | 引用
Better 说:
@RedNax:
其实在工作中我也有体会,就是调用后台接口传参的时候,把值设置成null和undefined还是有区别的,设置成null,不会忽略这个值,但是设置成undefined就会忽略,和JSON不会解析undefined有点类似
2016年9月22日 16:27 | # | 引用
zhbhun 说:
好像实际开发,除了本文提到的那几个地方会默认出现 undefined 外,其他大部分时候还是使用 null的,很少会自己去用 undefined 赋值。倒是读取值的时候需要特别小心,是 undefined 还是 null?
如果是 JSON 对象转为字符串时候,默认不转值为 undefined 的属性,而会转值为 null 的属性。这个实际上是 JSON 不会去转不存在的属性,这个应该跟需不需要 undefined 没关系吧!
如果没有了 undefined,所有不存在的属性也是返回 null 的话,好像也一样可以实现。JSON 对象对于没有设置过的属性就是当做不存在的,使用 Object.hasOwnProperty 返回 false。对于设置过值,不管是 null 还是其他什么值,都是返回 true。这样判断不存在属性一样可以实现,是否还需要 undefined 呢?
2016年9月27日 10:05 | # | 引用
DHclly 说:
@RedNax:
你的解释不错,很简洁明了
2017年3月24日 17:07 | # | 引用
y 说:
" 作为函数的参数,表示该函数的参数不是对象。"是什么用法
2017年4月28日 10:14 | # | 引用
Yu Er 说:
Null 空对象**指针**;
Undefined 是未初始化的**变量**。
2017年5月17日 11:36 | # | 引用
冴羽 说:
所以,阮老师,我十分的想知道就是 null 是一个值,用来表示 “没有对象”还是 null 就是表示“没有对象”???
2017年5月29日 23:07 | # | 引用
冴羽 说:
我想问阮老师,如果有两句话,"Object.prototype 没有原型"和 "Object.prototype 的原型为 null",阮老师会更赞同哪一句?
2017年6月 2日 19:07 | # | 引用
y sh 说:
null是地址;undefined是值;
2017年9月 3日 13:11 | # | 引用
ch 说:
请问把null作为函数的参数,表示该参数不是对象。
这句话的意思是什么?
2017年9月30日 16:18 | # | 引用
starryard 说:
已经踩了undefined的坑。有个参数没有在定义的时候初始化。有时结果正常,有时结果为NaN。
2017年10月 9日 17:29 | # | 引用
刘飞 说:
讲的很细节,谢谢
2017年12月13日 21:11 | # | 引用
mixdj小浩 说:
null简单来说就是“空气”,
undefined简单来说就是“虚有”,
2017年12月17日 15:11 | # | 引用
zhzbql 说:
2018年5月 3日 11:50 | # | 引用
gzg1023 说:
14就看到阮老师写Dart语言了,我到18年才知道这门语言
2018年10月15日 22:59 | # | 引用
美发 说:
var i;
i算定义了,还是没定义?单纯用语言上看,应该是声明(定义)了变量i,但是没赋值。可是这时i的类型是undefined
2019年12月28日 16:10 | # | 引用
Nuogz 说:
最简单使用理解就是`undefined`应由机器产生, 人工赋空值时任何情况都应使用`null`, 而不是`undefined`, 删除属性用`delete`, 不赋`undefined`
2020年5月26日 14:16 | # | 引用
soulkiller 说:
console.log(a)所显示的内容分析:
undefined表示变量a已经申明但从未被赋过值。
null表示变量a已申明且被赋过值,只不过这个值是一未创建的空对象。
{}表示变量a已申明且被赋过值,只不过这个值是已创建的空的对象。
Uncaught ReferenceError: a is not defined表示变量a没有被申明过。
2020年5月30日 12:35 | # | 引用
吴掌柜 说:
我觉得undefined表示可以不要这个属性,null表示可以有这个属性,就是这个属性值为空,不然访问一个对象没有的属性时为什么返回的是undefined而不是null
2021年1月21日 15:19 | # | 引用
紫菀 说:
var A = undefined;//声明变量未定义值 初始无值默认undefined
2021年3月11日 12:52 | # | 引用
ycllz 说:
undefined 已经声明的了,初始化就是undefined
2021年4月28日 11:40 | # | 引用
金三贵 说:
没事 多用就可以了
2021年8月18日 09:55 | # | 引用
Kai 说:
受教了,感谢老师分享!!
2021年9月12日 12:31 | # | 引用