为啥`数字(新布尔(假))=== 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
将对象转换为数字。布尔值true
和false
转换为1
和0
,Boolean
对象遵循相同的逻辑。另外,我不确定您所说的没有拆箱是什么意思。
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)
返回true
和false
为new Boolean(false)
。
这个方法被Number
函数和一元加号(+
)操作符在内部调用,所以代码变成:
Number(true)
等于1
,因为true
的数值为1。
您还可以在任何对象上实现valueOf
函数,使其具有自定义值,例如:
const object=
valueOf()
return 10
console.log(Number(object)) //10
【讨论】:
【参考方案4】:因为true
代表1
而false
代表0
0
是false
因为它们都是零元素 [半菱] [***上的半菱]。即使它们是不同的数据 类型,在它们之间进行转换是很直观的,因为它们 属于同构代数结构。
0
是加法的标识,乘法的标识为零。这适用于整数和有理数,但不是 IEEE-754 浮点 数字:0.0 * NaN = NaN
和0.0 * Infinity = NaN
。
false
是布尔 xor (⊻) 的标识,而布尔 and (∧) 的标识为零。如果布尔值表示为 0, 1(模 2 的整数集),您可以将 ⊻ 视为不带进位的加法,将 ∧ 视为 乘法。
""
和[]
是连接的标识,但有几个操作它们的意义为零。重复是其中之一,但 重复和连接不分布,所以这些操作 不要形成半环。这种隐式转换在小程序中很有帮助,但在 大可以使程序更难推理。只是其中之一 语言设计中的许多权衡。
[***上的森美林]:http://en.wikipedia.org/wiki/Semiring
引用from
阅读本文
1 = false and 0 = true?
【讨论】:
以上是关于为啥`数字(新布尔(假))=== 0`的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的自定义 JSONEncoder.default() 忽略布尔值?