Pat*_*nza 192 javascript
空数组是真的,但它们也等于false.
var arr = [];
console.log('Array:', arr);
if (arr) console.log("It's true!");
if (arr == false) console.log("It's false!");
if (arr && arr == false) console.log("...what??");
Run Code Online (Sandbox Code Playgroud)
我想这是由于等于运算符操作的隐式转换.
任何人都可以解释幕后发生的事情吗?
wil*_*ard 264
你在这里测试不同的东西.
if (arr)
对象调用(Array是JS中的Object实例)将检查对象是否存在,并返回true/false.
当你打电话if (arr == false)
你比较值这个对象和原始的false
价值.在内部,arr.toString()
被调用,返回一个空字符串""
.
这是因为toString
调用了Array返回Array.join()
,而空字符串是JavaScript中的一个虚假值.
Way*_*ett 58
关于这条线:
if (arr == false) console.log("It's false!");
Run Code Online (Sandbox Code Playgroud)
也许这些会有所帮助:
console.log(0 == false) // true
console.log([] == 0) // true
console.log([] == "") // true
Run Code Online (Sandbox Code Playgroud)
我相信正在发生的false
是强制布尔值以0
与对象(左侧)进行比较.该对象被强制转换为字符串(空字符串).然后,空字符串也被强制转换为数字,即零.所以最后的比较是0
== 0
,这是true
.
编辑:有关其工作原理的详细信息,请参阅规范的此部分.
从规则#1开始,这是正在发生的事情:
1.如果类型(x)与类型(y)不同,请转到步骤14.
适用的下一个规则是#19:
19.如果Type(y)是布尔值,则返回比较结果x == ToNumber(y).
结果ToNumber(false)
是0
,所以我们现在有:
[] == 0
Run Code Online (Sandbox Code Playgroud)
同样,规则#1告诉我们跳到第14步,但实际应用的下一步是#21:
21.如果Type(x)是Object而Type(y)是String或Number,则返回比较结果ToPrimitive(x)== y.
结果ToPrimitive([])
是空字符串,所以我们现在有:
"" == 0
Run Code Online (Sandbox Code Playgroud)
同样,规则#1告诉我们跳到第14步,但实际应用的下一步是#17:
17.如果Type(x)是String而Type(y)是Number,则返回比较结果ToNumber(x)== y.
结果ToNumber("")
是0
,让我们:
0 == 0
Run Code Online (Sandbox Code Playgroud)
现在,两个值都具有相同的类型,因此步骤从#1继续到#7,其中说:
7.如果x与y的数值相同,则返回true.
所以,我们回来了true
.
简单来说:
ToNumber(ToPrimitive([])) == ToNumber(false)
Run Code Online (Sandbox Code Playgroud)
为了补充韦恩的答案并尝试解释为什么要ToPrimitive([])
返回""
,有必要考虑“为什么”问题的两种可能的答案。第一种答案是:“因为规范说这就是JavaScript的行为方式。” 在ES5规范的9.1节中,将ToPrimitive的结果描述为Object的默认值:
通过调用对象的[[DefaultValue]]内部方法并传递可选提示PreferredType来检索对象的默认值。
第8.12.8节介绍了该[[DefaultValue]]
方法。此方法以“提示”作为参数,提示可以是String或Number。为了简化说明,如果提示为String,则[[DefaultValue]]
返回toString()
if 的值(如果存在)并返回原始值,否则返回的值valueOf()
。如果提示为Number,则toString()
和的优先级valueOf()
将颠倒,因此valueOf()
首先调用它,如果它是原始值,则返回其值。因此,是否[[DefaultValue]]
返回结果toString()
或valueOf()
取决于对象的指定PreferredType以及这些函数是否返回原始值。
默认的valueOf()
Object方法仅返回对象本身,这意味着除非类重写默认方法,否则valueOf()
仅返回Object本身。就是这种情况Array
。[].valueOf()
返回对象[]
本身。由于Array
对象不是原始对象,因此[[DefaultValue]]
提示无关紧要:数组的返回值将是的值toString()
。
引用David Flanagan的JavaScript:The Definitive Guide,顺便说一句,这是一本绝妙的书,应该是每个人获得以下类型问题的答案的第一本书:
此对象到数字的转换的详细信息说明了为什么将空数组转换为数字0,以及为什么具有单个元素的数组也可能转换为数字。数组继承了默认的valueOf()方法,该方法返回一个对象而不是原始值,因此数组到数字的转换依赖于toString()方法。空数组转换为空字符串。空字符串将转换为数字0。具有单个元素的数组将转换为与一个元素相同的字符串。如果数组包含单个数字,则该数字将转换为字符串,然后再转换回数字。
对“为什么”问题的第二种答案,除了“因为规范说了”以外,从设计的角度给出了为什么这种行为有意义的解释。关于这个问题,我只能推测。首先,如何将数组转换为数字?我能想到的唯一明智的可能性是将一个空数组转换为0,将任何非空数组转换为1。但是,正如Wayne的答案所揭示的,对于许多类型的比较,一个空数组都将转换为0。除此之外,很难想到Array.valueOf()的明智的原始返回值。因此,人们可能会争辩说,Array.valueOf()
使用默认值并返回Array本身更有意义,这就是toString()
ToPrimitive使用的结果。将数组转换为字符串而不是数字更有意义。
而且,正如弗拉纳根(Flanagan)的话所暗示的那样,该设计决策确实支持某些类型的有益行为。例如:
var a = [17], b = 17, c=1;
console.log(a==b); // <= true
console.log(a==c); // <= false
Run Code Online (Sandbox Code Playgroud)
此行为使您可以将单元素数组与数字进行比较,并获得预期的结果。