为什么“ null> = 0 && null <= 0”而不是“ null == 0”?


142

我必须编写一个例程,如果变量的类型为number,则将变量的值加1,否则将变量的赋值为0,其中变量的初始值为nullundefined

第一个实现是v >= 0 ? v += 1 : v = 0因为我认为没有数字会使算术表达式为假,但是由于null >= 0计算为真,所以这是错误的。然后,我了解到null行为类似于0,并且以下表达式均被评估为true。

  • null >= 0 && null <= 0
  • !(null < 0 || null > 0)
  • null + 1 === 1
  • 1 / null === Infinity
  • Math.pow(42, null) === 1

当然null不是0。null == 0被评估为false。这使看似重言式的表达成为(v >= 0 && v <= 0) === (v == 0)错误。

为什么null实际上不是0,却像0?


3
他在谈论Javascript。您的示例在PHP中。在PHP中,operator ==以一种特殊的方式比较值。您可以进行一些非常疯狂的比较,例如“ 10” ==“ 1e1”(这是事实)。如果使用operator ===,则会得到完全不同的结果,因为它会检查类型是否匹配以及值是否匹配。检查此链接:php.net/manual/en/language.operators.comparison.php
Pijusn 2012年

PHP的'=='运算符确实以“特殊”方式工作。
两位炼金术士2014年

如果您的要求是从1而不是0开始计数,则有一种非常简洁的方法可以递增最初为null或的计数器undefinedc = -~c // Results in 1 for null/undefined; increments if already a number
Ates Goral

1
undefined是变量值,用于尚未初始化的变量。null另一方面,是空对象值,不应与数字混合。null不应与数字组合,因此null不必表现得像数字。
马修(Matthew)

1
@AtesGoral-简洁,但不明显。值得提醒人们的是,每当做一些不明显的事情时,请添加注释以解释代码的作用。在大多数情况下,我认为它是“过早的优化”,因为它以牺牲清晰度为代价,从而获得了微不足道的性能提升。
制造商史蒂夫(Steve)

Answers:


207

您真正的问题似乎是:

为什么:

null >= 0; // true

但:

null == 0; // false

真正发生的是大于等于运算符>=)执行类型强制(ToPrimitive),提示类型为Number,实际上所有关系运算符都具有这种行为。

null等于运算符==)以特殊方式处理。在简短的,它只强制转换undefined

null == null; // true
null == undefined; // true

值,例如false'''0',和[]被受数字类型强制,它们都强迫到零。

您可以在“抽象相等比较算法”“抽象关系比较算法”中查看此过程的内部细节。

综上所述:

  • 关系比较:如果两个值都不是String类型,ToNumber则在两个值上都调用。这与+在前面添加a相同,后者将null强制转换为0

  • 平等比较:仅调用ToNumber字符串,数字和布尔值。


1
CMS,您的解释是null原语为0,所以0> = 0返回true,==返回false。但是根据ecma算法,如果Type(x)是Object而Type(y)是String或Number,返回比较结果ToPrimitive(x)== y。那么在此它应该返回true。请向我解释一下
Bharath muppa

对我来说,答案没有提供答案 -- null is treated in a special way by the Equals Operator (==). In a brief, it only coerces to undefined:什么?你能解释为什么null >= 0吗?:)
Andrey Deineko 2016年

@bharathmuppa @ andrey-deineko:CMS的其余答案在这里: 抽象关系比较算法 在第3点中进行了说明,即如果两个值都不是String类型,则在两个值上都调用ToNumber。这与+在前面添加a相同,后者将null强制转换为0。平等仅在字符串,数字和布尔值上调用ToNumber。
Michael Liquori

7
很好的描述,但我不喜欢它。在任何语言中(x == 0 || x> 0)应等于(x> = 0)。javascript是一种愚蠢的语言。
约翰·亨克尔

1
实际上,这只是规范中的一个错误(因为在数学上是错误的),并且与它无关,因为数百万个网站依赖于空比较^^'
mahieddine

14

我想扩展问题以进一步提高问题的可见性:

null >= 0; //true
null <= 0; //true
null == 0; //false
null > 0;  //false
null < 0;  //false

只是没有意义。像人类语言一样,这些事情也需要牢记。


1
如上所述,可以使用==如何处理null进行例外解释,否则在任何情况下都可以通过使用Number(nulll)将null转换为0
Ranka,

5

JavaScript具有严格和类型转换的比较

null >= 0;是真的,但是 (null==0)||(null>0)假的

null <= 0;是真的,但是(null==0)||(null<0)假的

"" >= 0 也是如此

对于关系抽象比较(<=,> =),在比较之前,将操作数首先转换为基元,然后转换为相同类型。

typeof null returns "object"

当type为object时,javascript尝试对对象进行字符串化(即null),将采取以下步骤(ECMAScript 2015):

  1. 如果PreferredType未通过,则hint设为“默认”。
  2. 否则,如果PreferredTypehintString,则hint设为“ string”。
  3. 否则PreferredTypehint数字,则为hint“数字”。
  4. 我们exoticToPrimGetMethod(input, @@toPrimitive)
  5. ReturnIfAbrupt(exoticToPrim)
  6. 如果exoticToPrim不是未定义,则
    a)令结果为Call(exoticToPrim, input, «hint»)
    b)ReturnIfAbrupt(result)
    c)如果Type(result)不是Object,则返回结果。
    d)引发TypeError异常。
  7. 如果hint为“默认”,则为“ hint数字”。
  8. 返回OrdinaryToPrimitive(input,hint)

提示的允许值为“默认”,“数字”和“字符串”。日期对象在内置ECMAScript对象中是唯一的,因为它们将“默认”等同于“字符串”。 所有其他内置ECMAScript对象都将“ default”等同于“ number”。(ECMAScript 20.3.4.45

所以我认为null转换为0。


1

我有同样的问题 !!。目前,我唯一的解决方案是分开。

var a = null;
var b = undefined;

if (a===0||a>0){ } //return false  !work!
if (b===0||b>0){ } //return false  !work!

//but 
if (a>=0){ } //return true !

,而不是做这可能是更清晰的:if (a!=null && a>=0)。这阐明了不仅仅>=自己做的原因:“ a可能为null(或未定义,也为'== null')”。
制造商史蒂夫(Steve)

0
console.log( null > 0 );  // (1) false
console.log( null == 0 ); // (2) false
console.log( null >= 0 ); // (3) true

从数学上来说,这很奇怪。最后一个结果指出“ null大于或等于零”,因此在上面的比较之一中,它必须为true,但它们均为false。

原因是相等检查==和比较的> < >= <=工作方式不同。比较会将null转换为数字,将其视为0。这就是(3)null >= 0true和(1)null > 0是的原因false

另一方面,==undefined和的相等性检查的null定义是,在没有任何转换的情况下,它们彼此相等,并且不等于其他任何东西。这就是为什么(2)null == 0false

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.