首页 文章

null与undefined及其在JavaScript中的行为

提问于
浏览
21

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

  • null == undefined 评估为 true

  • null + 1 等于1但 undefined + 1 等于 NaN

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

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

4 回答

  • 8

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

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

    Douglas Crockford有a very good series of talks about some of these issues .

  • 3

    First and foremost 虽然有很多语言没有两种方法可以实现这种类似的目的,但它们确实在Javascript中提供了不同但有些重叠的目的 . 之前有人问过"Why have both?",我发现this answer解释得相当好 . TL;DR :Javascript具有某些语言函数,这些函数生成缺少值而非非初始化值:

    • delete 'd值

    • 对象中不存在的属性

    • 缺少函数参数

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

    分别解决每个问题:

    null == undefined计算结果为true

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


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

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

    参数类型 - 结果未定义 - NaN Null - 0布尔值 - 如果参数为true,则结果为1 . 如果参数为false,则结果为0 . Number - 结果等于输入参数(无转换) .

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


    if(!null)计算结果为true,if(null)计算结果为false但null == false计算结果为false .

    如您所知 !Logical Not运算符,它在表达式上执行ToBoolean conversion . 这是一种截断 .

    if statementif (expr) )对expr执行隐式布尔比较 . 所以看看上面两个 if 语句中的expr类型:

    • if (!null) :expr是 !null ,给定逻辑非运算符( ! )的结果,它是 boolean .

    • if (null) :expr是 null ,表示未执行转换 .

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

    • if (!"" == !undefined) = true

    • if ("" == undefined) = false ,当然 .

  • 1

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

    null 用于"has no value."语言很少使用它,但主机环境经常使用它来表示"no value."例如, document.getElementById 返回 null 表示不存在的元素 . 类似地, HTMLScriptElement 的IE-only属性 onreadystatechange 设置为 null ,而不是 undefined ,表示虽然该属性存在,但它当前未设置 . 通常的好做法是在您自己的代码中使用 null ,而不是 undefined ,并在以下情况下保留 undefined

    undefined 用于"isn't even set or doesn't even exist."在很多情况下它是"default",例如访问未定义的属性(如非IE浏览器中的 HTMLScriptElementHTMLScriptElement ),没有 return 语句的方法的默认返回值,调用函数时参数少于声明的函数参数的默认值等 .

    通过这种方式,将 null 视为"valid value,"只是表示一些特殊的东西是有用的 . 而 undefined 更像是语言层面的东西 .

    当然,有一些边缘情况,这些推理并不完全成立;这些主要是出于遗产原因 . 但是存在差异,而且这是一个有意义的问题 .


    至于你的痛点,它们主要来自于操纵者的邪恶或类型强制:

    • null == undefined :不要使用 == 运算符,因为它本质上是一堆后向兼容性规则,在当时看起来很直观 .

    • null + 1 === 1undefined + 1 === NaN+ 运算符在评估之前确实将强制类型设置为 Number . 并且 null 强制执行 0+null === 0 )而 undefined 强制执行 NaNisNaN(+undefined) === true ) .

    • if (!null)if (null)null == false :if评估其参数的"truthiness"或"falsiness",这与 == 的乱七八糟的规则无关 . null 是假的, !null 是真的,但 == 的规则不允许 null == false .

  • 11

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

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

    我们可以用字符串和整数来表示相同的效果: "12" == 12 为true,但 "12" === 12 为false .

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

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

    你的最后一点证明了 null 一般的变化无常的性质 . 它是一种奇特的野兽,因为任何人都希望它的行为像 false 的替代名称,因为它不会那样工作 . 内置的 infinity 值可以以类似的奇怪方式运行,并且出于类似的原因 .

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

相关问题