null 与 undefined 及其在 JavaScript 中的行为

发布于 2024-11-28 20:53:55 字数 485 浏览 0 评论 0原文

因此,在对 javascript 中 null 和 undefined 的实现进行了激烈的争论/辩论/讨论之后,我希望有人解释一下实现背后的原因以及为什么它们在某些情况下有所不同。我发现一些特别的问题令人不安:

  • null == undefined 计算结果为 true
  • null + 1 等于 1 但 undefined + 1 equal NaN
  • if(!null) 计算结果为 true,if(null) 计算结果为 false,但 null == false 计算结果为 false。

我已经阅读了规范,并且知道如何达到结果,我正在寻找决定该规范的范式和原因。其中一些观点,尤其是第二点,考虑到第一点,感觉非常不一致。

So after a big argument/debate/discussion on the implementation of null and undefined in javascript I'd like somebody to explain the reasoning behind the implementation and why they differ in some circumstances. Some particular points I find troubling:

  • null == undefined evaluates to true
  • null + 1 equals 1 but undefined + 1 equal NaN
  • if(!null) evaluates to true and if(null) evaluates to false but null == false evaluates to false.

I've read the specification and I know how the results are reached, I'm looking for the paradigms and reasons that dictate this being the specification. Some of these points, especially the second one, given the first, feel very inconsistent.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

鯉魚旗 2024-12-05 20:53:55

简短而甜蜜的版本是,JavaScript 是由 Netscape 团队非常快速地设计和实现的,并且它存在一些不一致之处,例如您所指出的那些。

Internet Exploder 团队尽最大努力完全复制 JS,而且他们做得非常好,以至于不一致的地方也被复制了。当 Netscape 将 JS 标准化为 ECMAScript 时,MS 是其中的一部分,并且基本上表示不允许他们更改标准,因为这会破坏旧代码(现有系统惯性)。不一致之处已标准化,仅此而已。

Douglas Crockford 有关于其中一些问题的一系列非常好的演讲

The short and sweet version is that JavaScript was designed and implemented very rapidly by the Netscape team, and it had some inconsistencies such as the ones that you've pointed out.

The Internet Exploder team did its best to copy JS exactly and they did a damn good job of it to the point that the inconsistencies were copied as well. When Netscape went to get JS standardized as ECMAScript MS was a part of it and basically said that they weren't allowed to change the standard because it would break old code (existing systems inertia). The inconsistencies were standardized and that was that.

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

假装爱人 2024-12-05 20:53:55

首先,也是最重要的,虽然很多语言没有两种方法来实现类似的目的,但它们在 Javascript 中确实具有不同但有些重叠的目的。 “为什么两者都有?”之前曾在这里被问过,我发现 这个答案解释了这一点相当好。 TL;DR:Javascript 具有某些语言函数,可以生成缺失值,而不是未初始化值:

  • 删除 'd 值
  • 对象中不存在的属性
  • 缺少函数参数

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

分别解决每个问题:

  • null == undefined 计算结果为 true

请参阅此答案以获得最佳解释的这个。简而言之,抽象相等比较规范表明它们(非严格)相等。


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

运算符 + 充当 一元 +(数字转换)运算符或加法运算符,但两者都将参数路由到 ToNumber 规范,该规范表示:

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

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


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

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

if 语句 (if (expr)< /code>) 对 expr 执行隐式布尔比较。那么看一下上面两个 if 语句中 expr 的类型:

  • if (!null): expr 是 !null,给定逻辑非运算符 (!) 的结果,它是一个布尔值
  • if (null)exprnull 表示未执行任何转换。

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

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

First and foremost, while plenty of languages get away without having two methods for such similar purpose, they do serve distinct though somewhat overlapping purposes in Javascript. "Why have both?" has been asked here before, and I find that this answer explains this fairly well. TL;DR: Javascript has certain language functions that produce absent values as opposed to non-initialized values:

  • delete'd values
  • non-existent properties in an object
  • missing function parameters

As for the seeming contradictions in your question, they are actually quite easily explained by the spec. (I believe it can even be argued that the explanation is elegant, though there are probably those who would vehemently disagree.)

Addressing each one separately:

  • null == undefined evaluates to true

See this answer for the best explanation of this. In short, the abstract equality comparison specification says that they are (non-strictly) equal.


  • null + 1 equals 1 but undefined + 1 equal NaN

The operator + functions as either the unary + (numeric conversion) operator or addition operator, but both route the arguments to the ToNumber spec, which says:

Argument Type — Result
Undefined — NaN
Null — +0
Boolean — The result is 1 if the argument is true. The result is +0 if the argument is false.
Number — The result equals the input argument (no conversion).

In other words null + 1 becomes +0 + 1 and undefined + 1 becomes NaN + 1, which is always NaN.


  • if(!null) evaluates to true and if(null) evaluates to false but null == false evaluates to false.

As you know ! is the Logical Not operator, and it performs a ToBoolean conversion on the expression. It is a type of truncation.

The if statement (if (expr)) performs an implicit boolean comparison on expr. So take a look at the type of expr in both of the above if statements:

  • if (!null): expr is !null which, given the result of the logical not operator (!), is a boolean.
  • if (null) : expr is null which means no conversion was performed.

Since the logical not operator performs an actual conversion, the same thing happens in other cases as well, and is not actually a logical contradiction as you seem it to be:

  • if (!"" == !undefined) = true
  • if ("" == undefined) = false, of course.
第几種人 2024-12-05 20:53:55

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

null 用于“没有价值”。该语言很少使用它,但主机环境经常使用它来表示“没有价值”。例如,document.getElementById 对于不存在的元素返回 null。同样,HTMLScriptElement 的 IE 专用属性 onreadystatechange 设置为 null,而不是 undefined,以表示尽管该属性存在,但当前未设置。通常,最好在您自己的代码中使用 null 而不是 undefined,并在以下情况下保留 undefined

< code>undefined 用于“甚至没有设置或根本不存在”。在许多情况下它是“默认”,例如访问未定义的属性(例如非 IE 浏览器中 HTMLScriptElementonreadystatechange),不带 return 语句、当使用比声明的参数少的参数调用函数时函数参数的默认值等。

通过这种方式,将 null 视为一种“有效值”很有用,它只是一个表示特殊事物的值。而 undefined 更多的是语言级别的事情。

当然,在某些极端情况下,这些推理并不完全成立。这些主要是出于遗留原因。但还是有区别的,而且这种区别是有一定道理的。


特别是对于您的痛点,它们主要是由 == 运算符或类型强制的邪恶引起的:

  • null == undefined:不要使用 == 运算符,因为它本质上是一堆当时看起来很直观的向后兼容规则。
  • null + 1 === 1undefined + 1 === NaN+ 运算符将类型强制转换为 Number< /code> 在评估之前。 null 强制为 0 (+null === 0),而 undefined 强制为 NaN< /code> (isNaN(+undefined) === true)。
  • if (!null)if (null)null == false:if 评估其参数的“真实性”或“虚假性” ,这与 == 的规则混乱无关。 null 为假,!null 为真,但 == 的规则不允许 null == false.

They are best thought of as completely different objects used for different purposes:

null is used for "has no value." It is used pretty rarely by the language, but often used by the host environment to signify "no value." For example, document.getElementById returns null for nonexistant elements. Similarly, the IE-only property onreadystatechange for HTMLScriptElements is set to null, not undefined, to signify that though the property exists, it's currently not set. It is generally good practice to use null in your own code, instead of undefined, and leave undefined for the following cases:

undefined is used for "isn't even set or doesn't even exist." It is the "default" in many cases, e.g. accessing an undefined property (like onreadystatechange for HTMLScriptElement in non-IE browsers), the default return value from methods without return statements, the default value of function parameters when the function is called with fewer arguments than it declares, and the like.

In this way, it's useful to think of null as a "valid value," just one signifying something special. Whereas undefined is more of a language-level thing.

Sure, there are some edge cases where these reasonings don't entirely hold; those are mostly for legacy reasons. But there is a difference, and it's one that makes some deal of sense.


As for your pain points in particular, they mostly arise from the evil of the == operator or type coercion:

  • null == undefined: don't use the == operator, because it essentially is a mess of backward-compatibility rules that seemed intuitive at the time.
  • null + 1 === 1 vs. undefined + 1 === NaN: the + operator does type coercion to Number before evaluating. And null coerces to 0 (+null === 0) whereas undefined coerces to NaN (isNaN(+undefined) === true).
  • if (!null), if (null), null == false: if evaluates the "truthiness" or "falsiness" of its argument, which has nothing to do with the mess of rules for ==. null is falsy, and !null is truthy, but the rules for == don't let null == false.
傲鸠 2024-12-05 20:53:55

null == undefined 确实计算结果为 true,但 null === undefined 计算结果为 false。

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

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

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

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

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

不过 Javascript 确实有其怪异之处。您可能有兴趣阅读http://wtfjs.com/,其中包含大量奇怪的事情的条目JavaScript 确实如此。其中相当一部分与 nullundefined 有关(您知道吗,实际上可以重新定义内置 undefined 的值)对象?!),其中大多数都对实际发生的情况及其原因进行了解释。它可能有助于向您展示事情为何如此运作,并且绝对有助于向您展示应避免的事情!如果不出意外的话,看看人们试图对这种蹩脚的语言进行的一些谩骂,读起来会很有趣。

null == undefined does indeed evaluate to true, but null === undefined evaluates to false.

The difference in those two statements is the equality operator. Double-equal in Javascript will convert the two items to the same type before comparing them; for null == undefined, this means that the null is converted to an undefined variable before the comparison is done, hence the equality.

We can demonstrate the same effect with strings and integers: "12" == 12 is true, but "12" === 12 is false.

This example gives us an easier way to discuss your next point, about adding one to each of them. In the example above, adding 1 to the integer obviously gives 13, but with the string "12" + 1 gives us a string "121". This makes perfect sense, and you wouldn't want it any other way, but with a double-equal operator, the original two values were reported as equal.

The lesson here is to always use the triple-equal operator in preference to the double-equal, unless you have a specific need to compare variables of different types.

Your final point demonstrates the fickle nature of null in general. It is a peculiar beast, as anyone who's ever tried to work with a nullable database field will tell you. Null has a very specific definition in computer science, which is implemented in a similar way across multiple languages, so the situation you describe is not a special Javascript weirdness. Null is weird. Don't expect it to behave like an alternative name for false, because it doesn't work that way. The built-in infinity value can behave in a similarly bizarre way, and for similar reasons.

Javascript does have its share of weirdness though. You might be interested in reading http://wtfjs.com/, which has entries for a whole load of strange things that Javascript does. Quite a few of them are to do with null and undefined (did you know it's actually possible to redefine the value of the built-in undefined object?!), and most of them come with an explanation as to what's actually happening and why. It might be helpful in showing you why things work the way they do, and will definitely helpful in showing you things to avoid! And if nothing else, it makes for a good entertaining read to see some of the abuses people have tried throwing at the poor language.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文