空arrays在同一时间似乎是正确的和错误的

空数组是真的,但它们也等于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??"); 

我想这是由于平等运算符操作的隐式转换。

任何人都可以解释幕后发生了什么?

你在这里testing不同的东西。

if (arr)调用对象(Array是JS中Object的实例)将检查对象是否存在,并返回true / false。

当你调用if (arr == false)你比较了这个对象的和原始的false值。 在内部调用arr.toString() ,它返回一个空string""

这是因为在Array上调用的toString返回Array.join() ,而空string是JavaScript中的一个falsy值。

关于该行:

 if (arr == false) console.log("It's false!"); 

也许这些将有助于:

 console.log(0 == false) // true console.log([] == 0) // true console.log([] == "") // true 

我相信正在发生的事情是布尔的false被强制为0与对象(左侧)进行比较。 该对象被强制为一个string(空string)。 然后,空串被强制为一个数字,也就是零。 所以最后的比较是0 == 0 ,这是true

编辑:请参阅规格的这一部分,了解如何工作的细节。

这是发生了什么,从规则#1开始:

1.如果types(x)与types(y)不同,请转至步骤14。

下一个适用的规则是#19:

19.如果Type(y)是布尔型,则返回比较结果x == ToNumber(y)。

ToNumber(false)的结果是0 ,所以我们现在有:

 [] == 0 

规则#1再一次告诉我们跳到步骤#14,但实际应用的下一步是#21:

21.如果Type(x)是Object且Type(y)是String或Number,则返回比较结果ToPrimitive(x)== y。

ToPrimitive([])的结果是空string,所以我们现在有:

 "" == 0 

规则#1再一次告诉我们跳到步骤#14,但实际应用的下一步是#17:

17.如果Type(x)是String而Type(y)是Number,则返回比较结果ToNumber(x)== y。

ToNumber("")的结果是0 ,这留给我们:

 0 == 0 

现在,这两个值都是相同的types,所以步骤从#1继续到#7,它说:

7.如果x与y的数值相同,则返回true。

所以,我们回归true

简单来说:

 ToNumber(ToPrimitive([])) == ToNumber(false) 

在if(arr)中,如果arr是一个对象,则总是将其计算为ToBoolean,因为JavaScript中的所有对象都是真实的 。 (null不是一个对象!)

迭代方法评估[] == false 。 首先,如果==一边是原始图像,另一边是对象,则首先将对象转换为图元,如果两边都不是string ,则将两边转换为数字(如果两边都是string,则使用string比较)。 所以比较是迭代的, [] == false – > '' == false – > 0 == 0 – > true

为了补充韦恩的答案,并试图解释为什么ToPrimitive([])返回"" ,值得考虑“为什么”问题的两种可能的答案types。 第一种答案是:“因为规范说这是JavaScript的行为。” 在ES5规范中, 第9.1节描述了ToPrimitive的结果作为对象的默认值:

通过调用对象的[[DefaultValue]]内部方法来检索对象的默认值,并传递可选的提示PreferredType。

8.12.8节描述了[[DefaultValue]]方法。 该方法以“提示”作为参数,提示可以是string或数字。 为了简化问题,如果提示是String,那么[[DefaultValue]]返回toString()的值,如果它存在并返回一个原始值,否则返回valueOf()的值。 如果提示是Number,那么toString()valueOf()的优先级是颠倒过来的,所以valueOf()首先被调用,如果它是一个基元,它的返回值。 因此, [[DefaultValue]]是否返回toString()或者valueOf()取决于指定的对象的PreferredType以及这些函数是否返回原始值。

默认的valueOf() Object方法只返回对象本身,这意味着除非一个类重写默认的方法,否则valueOf()只返回Object本身。 Array就是这种情况。 [].valueOf()返回对象[]本身。 由于Array对象不是基元,所以[[DefaultValue]]提示是不相关的:数组的返回值将是toString()的值。

引用David Flanagan的JavaScript:“权威指南” ,顺便说一下,这本书是一本极好的书,应该是每个人都能得到这些types问题答案的第一位:

此对象到数字转换的详细信息解释了为什么空数组转换为数字0以及为什么具有单个元素的数组也可能转换为数字。 数组inheritance默认的valueOf()方法,该方法返回一个对象而不是原始值,所以数组到数字的转换依赖于toString()方法。 空数组转换为空string。 空string转换为数字0.带有单个元素的数组转换为与该元素相同的string。 如果数组包含单个数字,则该数字将转换为string,然后返回到数字。

“为什么”这个问题的第二种答案,除了“因为规范说”这个问题之外,给出了一些解释,为什么从devise的angular度来看这种行为是有意义的。 在这个问题上我只能推测。 首先,如何将数组转换为数字? 我能想到的唯一明智的可能性是将一个空数组转换为0,将任意非空数组转换为1.但是,正如Wayne的答案所显示的,无论如何,空数组将会转换为0。 除此之外,很难为Array.valueOf()想到一个明智的原始返回值。 所以人们可以争辩说,让Array.valueOf()成为默认值并返回数组本身就更有意义,从而导致Array.valueOf()成为ToPrimitive使用的结果。 将数组转换为string而不是数字更有意义。

而且,正如Flanagan所言,这种devise决定确实能够使某些types的有益行为成为可能。 例如:

 var a = [17], b = 17, c=1; console.log(a==b); // <= true console.log(a==c); // <= false 

这种行为允许您将单个元素数组与数字进行比较,并获得预期的结果。

在尝试使用knockout.js映射插件时,以上都没有帮助我,可能是因为“空数组”不是真的是空的。

我结束了使用: data-bind="if: arr().length"这个技巧。

这是特定的淘汰赛,而不是OP的问题,但也许它会帮助其他人浏览类似的情况在这里。