上面代码中,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)
5 + null
但是,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更多的表示值语义,虽然在数值上接近。
最近在看郑辉老师的书,讲编程范式和OOP思想,觉得获益匪浅,对各种语言也有了更深刻的认识,接下来要做的就是多接触体会了。
阮老师的博文我也很喜欢的说,讲的很通俗易懂,更多的细节可以自己去研究,很符合奥卡姆剃刀原则:)
虽然一开始我觉得就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字?)
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 脚本出现问题而被否决了……
window.onbeforeunload = function() {
return $body.hasClass('playing') ? '游戏仍在进行中!' : undefined;
IE 需要返回 undefined 才不会弹出提示。
undefined有几个意思:
1.undefined值本身,比如没有赋值的局部变量默认值就是undefined;
2.作为运行环境中全局变量的一个属性(浏览器环境中就是有window下有个undefined属性);
3.Undefined类型
参考:http://modernweb.com/2013/12/09/exploring-the-abyss-of-null-and-undefined-in-javascript/
这样说可能更好理解:
undefined 是期房 X小区X栋X单元,房子没建呢,更别说住人了,开发商也可能卷款跑路,房子也可能烂尾
null 是待售现房,有房子了,暂时还没人住,不管以后有没有人住,至少房子在那里
你找X小区X栋X单元的业主,如果房子还没建,那就是undefine;如果建了没卖,就是null
虽然一开始我觉得就null和undefined写一篇文章太大惊小怪了,不过考虑了一下其实蛮多东西值得挖掘的:
1.null 和 undefined在现代JS语义里面是有明确区别的:
null 表示一个值被定义了,定义为“空值”;
undefined 表示根本不存在定义。
这个确实比阮老师的更明确一些,阮老师的博文已经看了很多篇了,非常喜欢其页面布局,给人一种清新自然的感觉,没有一点看教科书的疲惫感。其对javascript的某些方法思想方面的讲解让人能够很容易理解,可是其对于一些基本术语的描述就没有权威书籍讲解得正确了,如果抱着纯接收式的心态来阅读,就很容易走偏。
其实我觉得这个样子理解是不是要好些:
js在运行前还有一个 预加载 预加载的目的是 要事先构造运行环境例如全局环境,函数运行环境,还要构造作用域链,而环境和作用域的构造的核心内容就是 指定好变量属于哪个范畴,因此在javascript语言里变量的定义是在预加载完成而非在运行时期。
那么问题来了: 在运行期,就会发生赋值行为等等,没有发生赋值行为的默认就会把它设置为undefined,所以这里可以这样理解null和undefined的区别在于有没有发生赋值行为
通过对你这两句话的理解,下面的语句打印结果如下:var x; console.log(x);//? console.log(y)//undefined
但是实际是console.log(x);//undefined console.log(y)//y is not defined
引用RedNax的发言:
虽然一开始我觉得就null和undefined写一篇文章太大惊小怪了,不过考虑了一下其实蛮多东西值得挖掘的:
1.null 和 undefined在现代JS语义里面是有明确区别的:
null 表示一个值被定义了,定义为“空值”;
undefined 表示根本不存在定义。
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)。
感觉 null 和 undefined 在实际开发中容易混淆,增加了编程负担。例如,经常要判断某个变量是否非 undefined 和 null,还需要这么写 typeof v !== 'undefined && null !== null。还有,ES6 对象解构时,只有 undefined 的属性才支持默认值,结合本文来看,null 应该是代表一个特殊的值(空值),这个在实际开发中区别对待是否有意义 —— 我在大部分的代码中都是要给 null 和 undefined 写个默认值的。除了文中提到的历史原因外,是否都是把 null 和 undefined 当成其他语言的 null/None 来处理,有哪些场景是需要区别对待的?
引用zhbhun的发言:
感觉 null 和 undefined 在实际开发中容易混淆,增加了编程负担。例如,经常要判断某个变量是否非 undefined 和 null,还需要这么写 typeof v !== 'undefined && null !== null。还有,ES6 对象解构时,只有 undefined 的属性才支持默认值,结合本文来看,null 应该是代表一个特殊的值(空值),这个在实际开发中区别对待是否有意义 —— 我在大部分的代码中都是要给 null 和 undefined 写个默认值的。除了文中提到的历史原因外,是否都是把 null 和 undefined 当成其他语言的 null/None 来处理,有哪些场景是需要区别对待的?
真的需要 undefined 吗?假设 JS 没有 undefined 的话,会怎样?
1. 变量声明,初始化值为 null
2. 调用函数,参数默认值为 null
3. 对象没有赋值的属性,默认为 null
4. 函数没有返回值,默认返回 undefined
不考虑历史问题,除了第三点导致无法区分对象是存在属性外,其他几点会还会带来什么样的问题?
对于第三点,完全可以通过另外的接口来判断该对象是否存在该属性,这有点类似于 Java 的 Map,不存在的 key 也是返回 null。而且,JS 本身也是有接口判断对象是否存在某个属性的。
上面给自己提了好几个问题,实在是搞不懂,希望大家帮忙指导!
好像实际开发,除了本文提到的那几个地方会默认出现 undefined 外,其他大部分时候还是使用 null的,很少会自己去用 undefined 赋值。倒是读取值的时候需要特别小心,是 undefined 还是 null?
如果是 JSON 对象转为字符串时候,默认不转值为 undefined 的属性,而会转值为 null 的属性。这个实际上是 JSON 不会去转不存在的属性,这个应该跟需不需要 undefined 没关系吧!
如果没有了 undefined,所有不存在的属性也是返回 null 的话,好像也一样可以实现。JSON 对象对于没有设置过的属性就是当做不存在的,使用 Object.hasOwnProperty 返回 false。对于设置过值,不管是 null 还是其他什么值,都是返回 true。这样判断不存在属性一样可以实现,是否还需要 undefined 呢?
parseInt和parseFloat 都是用来将String分析为Numer的,你传的这两个都不是字符串,因此该函数首先将其隐性类型转换为字符串,null转为空字符串,undefined转为‘undefined’,然后根据这两个函数的定义,这两个字符串分析不出有效数字的情况下 返回NaN;
注意,这两个函数的作用是‘分析’,而不是‘转化’
undefined表示变量a已经申明但从未被赋过值。
null表示变量a已申明且被赋过值,只不过这个值是一未创建的空对象。
{}表示变量a已申明且被赋过值,只不过这个值是已创建的空的对象。
Uncaught ReferenceError: a is not defined表示变量a没有被申明过。