为什么在条件结构中,空的JavaScript数组会被评估为true?

192
我在我的代码中遇到了很多错误,因为我期望这个表达式:Boolean([]); 的结果是false。
但事实并非如此,它的结果是true。
因此,可能返回[]这样的函数,像这样:
// Where myCollection possibly returned [ obj1, obj2, obj3] or []
if (myCollection)
{
  // ...

} else
{
  // ...
}

没有做预期的事情。

我是否错误地认为 [] 一个空数组应该被判断为假?

另外,这个行为在所有浏览器中一致吗?还是也存在一些陷阱?顺便说一下,我在 Google Chrome 中观察到了这种行为。


12
数组是对象,对象的真值为真。只需请求数组长度,如果不为零,则为真。当您显式地将其转换为布尔类型时,数组首先变为空字符串,然后空字符串变为false。 - dandavis
2
为什么不使用 myCollection.length > 0 - Steve
2
@Steve - 如果'myCollection'恰好为'null'或'undefined',那么这是行不通的。您需要使用'if(myCollection && myCollection.length>0)'。 - Ted Hopp
@TedHopp - 当然...我只是指出myCollection.length > 0提供了一个布尔值,正在做OP要求的事情...他仍然需要从那里开始努力。 - Steve
大家不需要使用 myArray.length > 0,因为如果长度为0,它将返回0,即false,如果它返回任何其他大于0的长度,则默认为true。 - Kunok
8个回答

209

来自 http://www.sitepoint.com/javascript-truthy-falsy/

以下值始终为假:

  • false
  • 0(零)
  • 0n(BigInt 零)
  • ""(空字符串)
  • null
  • undefined
  • NaN(一个特殊的数值,表示不是数字!)

所有其他值都为真,包括"0"(带引号的零),"false"(带引号的假),空函数,空数组([])和空对象({})。

关于为什么会这样,我猜测这是因为 JavaScript 数组只是一种特定类型的对象。特别处理数组将需要额外的开销来测试Array.isArray()。此外,如果真正的数组在此上下文中行为不同于其他类似数组的对象,这可能会很困惑,而使所有类似数组的对象行为相同将会更加昂贵。


60
如果你测试表达式[] == false,它会被计算为true - m.rufca
4
@m.rufca 请查看 https://dev59.com/Y2035IYBdhLWcg3wVeXn - Barmar
15
这并没有回答问题,问题是为什么。为什么一个空数组是真值,而一个空字符串是假值?作为一项故意的设计决策,这感觉非常糟糕。 - Esa Lindqvist
1
@EricDuminil 我在9年前回答时不知道BigInt。但我认为可以说所有形式的零都是falsey。 - Barmar
1
@EricDuminil 已更新 - Barmar
显示剩余9条评论

49
你应该检查那个数组的.length属性,以确定它是否包含任何元素。
if (myCollection) // always true
if (myCollection.length) // always true when array has elements
if (myCollection.length === 0) // same as is_empty(myCollection)

15

虽然 [] 等于 false,但它被计算为 true

是的,这听起来很糟糕,或者至少有些令人困惑。看看这个例子:

const arr = [];
if (arr) console.log("[] is truethy");
if (arr == false) console.log("however, [] == false");

在实践中,如果您想检查某个东西是否为空,则检查length。(?.运算符确保还涵盖了null。)

const arr = []; // or null;
if (!arr?.length) console.log("empty or null")


5
哇,可选链运算符 ?.。好像很新(而且很有用)。谢谢让我学到了新知识。 - Константин Ван
1
@КонстантинВан 我猜它需要一个关于兼容性的警告。:-) 谢谢你指出这一点。 - bvdb
1
为什么我现在才发现可选链操作符?以及相关的空值合并运算符。太好了!谢谢。 - Dave

13
[]==false  // returns true

这个条件语句返回true,因为使用了抽象相等算法,如此在ECMA规范第11.9.3节中所述。

如果按照上面提到的算法运行:

第一次迭代中,满足的条件是:

Step 7: If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).

因此上述条件转化为 -> [] == 0

现在在第二次迭代中,满足的条件是[] == 0

Step 9: If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.

因为[]是一个对象,将其转换为原始值后,会变成一个空字符串''

因此,上述条件转化为 -> '' == 0

第三次迭代中,满足的条件是:

Step 5: If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.

由于我们知道空字符串''是一个falsy值,因此将空字符串转换为数字会返回值0

因此,我们的条件将转化为 -> 0 == 0

第四次迭代中,满足的是类型相等且数字相等的第一个条件。

因此,[] == false的最终值缩减为0 == 0,其结果为true。

希望这回答了你的问题。否则,你也可以参考这个youtube视频


1
我已经期待这个答案将近十年了。 - Wyck
1
终于有一个参考了语言规范的答案了。 - bvdb
![] == false // returns true as well - EliSherer
是的,@EliSherer,这是预期的。重点关注上述算法的第二次迭代,其中对象被转换为原始值,(![]).toString(),它将在内部导致空字符串,即falsy值。因此,false这意味着第三和第四次迭代保持不变,并且上面评论的结果也是true。请记住,我的朋友,!([]==false)将是false ![]==false将是true - Abir

1
我怀疑这与离散数学和条件语句有关。条件语句有两个部分,但在第一部分不存在的情况下,无论第二部分如何,它都会返回一个称为“虚假真实”的东西。
以下是维基百科页面中关于虚假真实的示例:
“房间里所有手机都已关闭”这个说法在没有手机在房间里时是正确的。在这种情况下,“房间里所有手机都已开启”的说法也是虚假的真实”。
维基百科甚至稍后特别提到了JavaScript。 https://en.wikipedia.org/wiki/Vacuous_truth#:~:text=In%20mathematics%20and%20logic%2C%20a,the%20antecedent%20cannot%20be%20satisfied.&text=One%20example%20of%20such%20a,Eiffel%20Tower%20is%20in%20Bolivia%22.

0

就像在JavaScript中,一切都是对象,因此对于falsy和empty,我使用以下条件:

if(value && Object.keys(value).length){
    // Not falsy and not empty
}
else{
    // falsy or empty array/object
}

0
在JavaScript中,空字符串和空数组都被视为假值。当在布尔上下文中进行评估时,它们被视为false。对于这个方面可能存在一些困惑。
为了澄清,在JavaScript中,以下值被认为是假值:
1. false:布尔值false。 2. 0:数字零。 3. NaN:非数字,表示无效或不可表示的值。 4. null:表示有意缺少任何对象值。 5. undefined:表示已声明但未赋值的变量。 6. ''(空字符串)。 7. document.all:不再推荐使用的历史遗留物。
当在布尔上下文中遇到这些值时,它们会被强制转换为false,例如在if语句或条件表达式中。
现在,值得注意的是,一个空数组[]仍然是一个有效的JavaScript对象,并被视为真值。然而,在布尔上下文中使用时,比如在if语句中,空数组会自动转换为其布尔表示,即false。
例如:
if ([]){
  console.log("This will not be executed.");
}

if (''){
  console.log("This will not be executed either.");
}

if (0){
  console.log("Nor this.");
}

if (null){
  console.log("Neither this.");
}

if (undefined){
  console.log("Or this.");
}

在上面的代码中,由于括号内的所有值都被视为假值,因此不会执行if块中的任何语句。
因此,在JavaScript中,空字符串和空数组都是假值,意味着在布尔上下文中评估时会被视为假。

0
另外要补充的是,JavaScript 中的所有对象(数组也是对象)都以链接的形式存储在内存中,而这些链接始终不为 null 或零,这就是为什么 Boolean({}) === trueBoolean([]) === true 的原因。
此外,这也是同样的对象(按值复制而非链接)始终不相等的原因。
{} == {} // false

let a = {};
let b = a; // copying by link
b == a // true

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接