因此,在javascript中对null和undefined的实现进行了大的争论/辩论/讨论后,我想让某人解释实现背后的原因以及它们在某些情况下的不同之处。我发现一些特别的问题令人不安:
null == undefined
评估为true
null + 1
等于1,但undefined + 1
等于NaN
if(!null)
评估为true,if(null)
评估为false,但null == false
评估为false。我已经阅读了规范并且我知道如何达到结果,我正在寻找规范这个规范的范例和原因。其中一些要点,特别是第二点,给出第一点,感觉非常不一致。
答案 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 + 1
而undefined + 1
变为NaN + 1
,始终为NaN
。
- if(!null)的计算结果为true,if(null)的计算结果为false,但null == false的计算结果为false。
如您所知!
是Logical Not运算符,它会对表达式执行ToBoolean 转换。这是一种截断。
if
statement(if (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
强制null
(0
)而+null === 0
强制undefined
(NaN
)。isNaN(+undefined) === true
,if (!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所做的大量奇怪事情的条目。其中有很多与null
和undefined
有关(你知道它实际上可以重新定义内置undefined
对象的价值吗?!),其中大部分都是我们会解释实际发生的事情和原因。它可能有助于向您展示为什么事情按照他们的方式工作,并且肯定有助于向您展示要避免的事情!如果不出意外,它会让人看到一些有趣的阅读,以便看到人们试图用可怜的语言抛出的一些虐待行为。