null与undefined及其在JavaScript中的行为

时间:2011-08-09 18:10:56

标签: javascript ecmascript-5

因此,在javascript中对null和undefined的实现进行了大的争论/辩论/讨论后,我想让某人解释实现背后的原因以及它们在某些情况下的不同之处。我发现一些特别的问题令人不安:

  • null == undefined评估为true
  • null + 1等于1,但undefined + 1等于NaN
  • if(!null)评估为true,if(null)评估为false,但null == false评估为false。

我已经阅读了规范并且我知道如何达到结果,我正在寻找规范这个规范的范例和原因。其中一些要点,特别是第二点,给出第一点,感觉非常不一致。

4 个答案:

答案 0 :(得分:11)

简短而甜蜜的版本是Netscape团队非常迅速地设计和实现了JavaScript,它有一些不一致的地方,比如你已经指出的那些。

Internet Exploder团队尽力复制JS ,他们做得非常好,以至于不一致也被复制了。当Netscape将JS标准化时,因为ECMAScript MS是其中的一部分,并且基本上说他们不允许更改标准,因为它会破坏旧代码(现有系统惯性)。不一致是标准化的,那就是。

道格拉斯·克罗克福德有a very good series of talks about some of these issues

答案 1 :(得分:8)

首先是,虽然很多语言在没有两种方法用于此类目的的情况下离开,但它们在Javascript中提供了不同但有些重叠的目的。 “为什么两者兼而有之?”之前有人问过这个问题,我发现this answer解释得相当好。 TL; DR :Javascript具有某些语言函数,这些函数会产生缺少值而不是非初始化值:

  • delete'd值
  • 对象中不存在的属性
  • 缺少功能参数

至于你问题中看似矛盾的问题,实际上很容易通过规范来解释。 (我相信甚至可以说这种解释很优雅,尽管可能会有人强烈不同意。)

分别处理每一个:

  
      
  • null == undefined计算结果为真
  •   

有关此问题的最佳解释,请参阅this answer。简而言之,abstract equality comparison规范说它们(非严格地)相等。


  
      
  • null + 1等于1但未定义+ 1等于NaN
  •   

运算符+可用作unary +(数字转换)运算符或addition运算符,但两者都将参数路由到ToNumber规范,其中说明:< / p>

  

参数类型 - 结果
  未定义 - NaN
  空 - +0
  Boolean - 如果参数为true,则结果为1。如果参数为假,则结果为+0   Number - 结果等于输入参数(无转换)。

换句话说,null + 1变为+0 + 1undefined + 1变为NaN + 1,始终为NaN


  
      
  • if(!null)的计算结果为true,if(null)的计算结果为false,但null == false的计算结果为false。
  •   

如您所知!Logical Not运算符,它会对表达式执行ToBoolean 转换。这是一种截断。

if statementif (expr))对 expr 执行隐式布尔比较。因此,请查看以上两个if语句中 expr 的类型:

  • if (!null) expr !null,在给定逻辑非运算符(!)的结果的情况下,布尔值
  • if (null) expr null,表示未进行任何转化。

由于逻辑非运算符执行实际转换,在其他情况下也会发生同样的事情,并且实际上并不像您看起来那样是逻辑矛盾:

  • if (!"" == !undefined) = true
  • if ("" == undefined) = false ,当然。

答案 2 :(得分:4)

最好将它们视为用于不同目的的完全不同的对象:

null 用于“没有价值”。语言很少使用它,但主机环境经常使用它来表示“没有价值”。例如,document.getElementById会为不存在的元素返回null。同样,onreadystatechange的仅IE属性HTMLScriptElement设置为null,而不是undefined,表示虽然属性存在,它目前未设置。一般来说,最好在自己的代码中使用null,而不是undefined,并在以下情况下使用undefined

undefined 用于“甚至没有设置或甚至不存在”。在许多情况下,这是“默认”,例如访问未定义的属性(如非IE浏览器中onreadystatechange的{​​{1}}),没有HTMLScriptElement语句的方法的默认返回值,调用函数时的函数参数的默认值参数少于声明的参数,等等。

通过这种方式,将return视为“有效值”是有用的,只是表示一些特殊的东西。而null更像是语言层面的东西。

当然,有些边缘情况下这些推理并不完全成立;这些主要是出于遗产原因。但是有一点不同,而且这是有道理的。


至于你的痛点,它们主要来自undefined操作员的邪恶或类型强迫:

  • ==:不要使用null == undefined运算符,因为它本质上是一堆向后兼容的规则,当时看起来很直观。
  • ==null + 1 === 1的对比:undefined + 1 === NaN运算符在评估之前会对+键入强制。并Number强制null0)而+null === 0强制undefinedNaN)。
  • isNaN(+undefined) === trueif (!null)if (null):如果评估其参数的“真实性”或“虚假性”,则与{{1}的规则混乱无关}。 null == false是假的,==是真的,但null的规则不允许!null

答案 3 :(得分:1)

null == undefined确实评估为true,但null === undefined评估为false。

这两个语句的区别在于等于运算符。在比较它们之前,Javascript中的双重相等会将两个项目转换为相同的类型;对于null == undefined,这意味着在完成比较之前null被转换为未定义的变量,因此是相等的。

我们可以使用字符串和整数来表示相同的效果:"12" == 12为真,但"12" === 12为假。

此示例为我们提供了一种更简单的方式来讨论您的下一个要点,即为每个点添加一个。在上面的示例中,向整数添加1显然会提供13,但字符串"12" + 1会为我们提供字符串"121"。这是完全合理的,你不会想要任何其他方式,但是使用双等运算符,原始的两个值被报告为相等。

这里的教训是始终使用三重等于运算符而不是双等号,除非您特别需要比较不同类型的变量。

你的最后一点证明了null一般的变幻无常的性质。这是一个奇特的野兽,因为任何试图使用可空数据库字段的人都会告诉你。 Null在计算机科学中有一个非常具体的定义,它以类似的方式在多种语言中实现,因此您描述的情况不是特殊的Javascript怪异。空虚很奇怪。不要指望它的行为类似于false的替代名称,因为它不会那样工作。内置的infinity值可能会以类似的奇怪方式运行,并且出于类似的原因。

Javascript确实有它的奇怪之处。您可能有兴趣阅读http://wtfjs.com/,其中包含Javascript所做的大量奇怪事情的条目。其中有很多与nullundefined有关(你知道它实际上可以重新定义内置undefined对象的价值吗?!),其中大部分都是我们会解释实际发生的事情和原因。它可能有助于向您展示为什么事情按照他们的方式工作,并且肯定有助于向您展示要避免的事情!如果不出意外,它会让人看到一些有趣的阅读,以便看到人们试图用可怜的语言抛出的一些虐待行为。