为啥`数字(新布尔(假))=== 0`

Posted

技术标签:

【中文标题】为啥`数字(新布尔(假))=== 0`【英文标题】:Why `Number(new Boolean(false)) === 0`为什么`数字(新布尔(假))=== 0` 【发布时间】:2020-04-22 23:54:07 【问题描述】:

Boolean(new Boolean(...)) === true 因为new Boolean(...) 是一个对象。

但为什么是Number(new Boolean(false)) === 0 (+new Boolean(false) === 0) 和Number(new Boolean(true)) === 1?为什么不NaN*?

为什么第一个例子没有拆箱,而第二个例子有?


*isNaN(Number()) === true

【问题讨论】:

Number 调用toPrimitive,这将解开布尔值。 Number 将对象转换为数字。布尔值truefalse 转换为10Boolean 对象遵循相同的逻辑。另外,我不确定您所说的没有拆箱是什么意思。 Boolean 不这样做,它有一个非常简单的表,它遵循,结果应该是true 还是false。如您所见,在该表中,对象被解释为true。 “为什么”是一个难题,但规范就是这样。另一个例子是Number( valueOf: _ => 4) === 4 【参考方案1】:

正如@ASDFGerte 提到的。这是因为Number() constructor 调用的ToNumber() 方法将调用.ToPrimitive() on the argument if an object is passed。这就是为什么它被视为布尔基元而不是对象的原因。

【讨论】:

只是提到ToPrimitive 是一个内部函数(连同ToNumber),它调用[Symbol.toPrimitive].valueOf.toString 方法(以不同的顺序),而不是与对象上的 .toPrimitive 方法混淆,这在 JS 中没有特殊含义。【参考方案2】:

isNaN(数字()) === 真

虽然这是正确,但我认为您将an 对象与Boolean 对象等同起来,两者并不等同。

让我们从最重要的事情开始——Number 将其给定的参数转换为数字。但是,它不会随意这样做——有rules about numeric conversion,当涉及到对象时,它并不像“所有对象都是NaN”那么简单。考虑一下:

const obj0 = 

const obj1 = 
  toString() 
    return 1;
  


const obj2 = 
  toString() 
    return 1;
  ,
  valueOf() 
    return 2;
  


const obj3 = 
  toString() 
    return 1;
  ,
  valueOf() 
    return 2;
  ,
  [Symbol.toPrimitive]() 
    return 3;
  


const obj4 = Object.create(null);

console.log(Number(obj0)); //NaN
console.log(Number(obj1)); //1
console.log(Number(obj2)); //2
console.log(Number(obj3)); //3
console.log(Number(obj4)); //Error

转换为数字时,并非所有对象都相等。有些碰巧比其他的更不平等。

Number 被赋予一个对象时,它会通过一个过程将其转换为to a primitive,并带有一个数字的首选项(提示)。为此,它将经过以下步骤:

    确定提示为“数字”。 检查对象是否实现@@toPrimitive 方法。 如果是这样,它将使用提示(“数字”)调用它 如果不存在,它将寻找valueOf 方法。 这样做是因为提示是“数字”,所以会先检查valueOf。 如果不存在,那么它将检查toString 方法 同样,这是基于“数字”的提示。如果提示是“字符串”,则最后两步将相反。 如果不存在,则引发错误。

一旦找到合适的方法,它就会被执行并且返回的值将被转换成数字。

我们还没有接触过Boolean - 这就是通用Number 进行转换的方式。因此,总而言之 - 如果对象实现了正确的功能, 可以转换为原始数字。

Boolean 对象确实 实现了正确的功能 - 它们 have a valueOf method 返回它们持有的原始布尔值:

const T1 = new Boolean(true);
const T2 = new Boolean(true);

console.log("T1.valueOf()", T1.valueOf());
console.log("typeof T1.valueOf()", typeof T1.valueOf());
console.log("T1 === T2", T1 === T2);
console.log("T1.valueOf() === T2.valueOf()", T1.valueOf() === T2.valueOf());

所以,在这种情况下: Number(new Boolean(true)) = Number(new Boolean(true).valueOf()) = Number(true)

如果我们稍微概括一下,那么:Number(new Boolean(bool)) = Number(bool)

ToNumber conversion 我们知道true 变成了1,而false 变成了0。因此相等Number(new Boolean(false)) === 0 是完全合理的,因为Number(false) 确实是0。与Number(new Boolean(true)) === 1 相同。

【讨论】:

【参考方案3】:

布尔对象有一个valueOf方法,可以在类型转换中自定义对象的原始值。

Boolean#valueOf()new Boolean(true) 返回truefalsenew Boolean(false)

这个方法被Number函数和一元加号(+)操作符在内部调用,所以代码变成:

Number(true)

等于1,因为true的数值为1。


您还可以在任何对象上实现valueOf 函数,使其具有自定义值,例如:

const object=
    valueOf()
        return 10
    

console.log(Number(object)) //10

【讨论】:

【参考方案4】:

因为true代表1

false代表0

0false 因为它们都是零元素 [半菱] [***上的半菱]。即使它们是不同的数据 类型,在它们之间进行转换是很直观的,因为它们 属于同构代数结构。

0 是加法的标识,乘法的标识为零。这适用于整数和有理数,但不是 IEEE-754 浮点 数字:0.0 * NaN = NaN0.0 * Infinity = NaN

false 是布尔 xor (⊻) 的标识,而布尔 and (∧) 的标识为零。如果布尔值表示为 0, 1(模 2 的整数集),您可以将 ⊻ 视为不带进位的加法,将 ∧ 视为 乘法。

""[] 是连接的标识,但有几个操作它们的意义为零。重复是其中之一,但 重复和连接不分布,所以这些操作 不要形成半环。

这种隐式转换在小程序中很有帮助,但在 大可以使程序更难推理。只是其中之一 语言设计中的许多权衡。

[***上的森美林]:http://en.wikipedia.org/wiki/Semiring

引用from

阅读本文

1 = false and 0 = true?

【讨论】:

以上是关于为啥`数字(新布尔(假))=== 0`的主要内容,如果未能解决你的问题,请参考以下文章

在c中将布尔结果打印为“假”或“真”的最佳方法?

为啥我的自定义 JSONEncoder.default() 忽略布尔值?

为啥 list.append 在布尔上下文中评估为 false? [复制]

数字布尔值字符串列表

(14)awk布尔值比较和逻辑运算

为啥这个 if 语句不返回布尔值?