Javascript 空数组似乎同时等于 true 和 false

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5491605/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 17:25:40  来源:igfitidea点击:

Empty arrays seem to equal true and false at the same time

javascript

提问by Patonza

Empty arrays are true but they're also equal to 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??");

I guess this is due to the implicit conversion operated by the equality operator.

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

Can anyone explain what's going on behind the scenes?

谁能解释一下幕后发生了什么?

回答by wildcard

You're testing different things here.

你在这里测试不同的东西。

if (arr)called on object (Array is instance of Object in JS) will check if the object is present, and returns true/false.

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

When you call if (arr == false)you compare valuesof this object and the primitive falsevalue. Internally, arr.toString()is called, which returns an empty string "".

当你打电话if (arr == false)你比较这个对象和原始的false价值。在内部,arr.toString()被调用,它返回一个空字符串""

This is because toStringcalled on Array returns Array.join(), and empty string is one of falsy values in JavaScript.

这是因为toString在 Array 上调用返回Array.join(),而空字符串是 JavaScript 中的假值之一。

回答by Wayne

Regarding the line:

关于线路:

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

Maybe these will help:

也许这些会有所帮助:

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

What I believe is happening is that the boolean falseis coerced to 0for comparison with an object (the left-hand side). The object is coerced to a string (the empty string). Then, the empty string is coerced into a number, as well, namely zero. And so the final comparison is 0== 0, which is true.

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

Edit:See this section of the specfor details on exactly how this works.

编辑:有关具体如何工作的详细信息,请参阅规范的这一部分

Here's what's happening, starting at rule #1:

下面是正在发生的事情,从规则 #1 开始:

1. If Type(x) is different from Type(y), go to step 14.

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

The next rule that applies is #19:

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

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

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

The result of ToNumber(false)is 0, so we now have:

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

[] == 0

Again, rule #1 tells us to jump to step #14, but the next step that actually applies is #21:

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

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

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

The result of ToPrimitive([])is the empty string, so we now have:

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

"" == 0

Again, rule #1 tells us to jump to step #14, but the next step that actually applies is #17:

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

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

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

The result of ToNumber("")is 0, which leaves us with:

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

0 == 0

Now, both values have the same type, so the steps continue from #1 until #7, which says:

现在,两个值具有相同的类型,因此步骤从 #1 继续到 #7,即:

7. If x is the same number value as y, return true.

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

So, we return true.

所以,我们返回true

In brief:

简单来说:

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

回答by cjg

To supplement Wayne'sanswer and to try to explain why ToPrimitive([])returns "", it's worth considering two possible types of answers to the 'why' question. The first type of answer is: "because the specification says this is how JavaScript will behave." In the ES5 spec, section 9.1, which describes the result of ToPrimitive as a default value for an Object:

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

The default value of an object is retrieved by calling the [[DefaultValue]] internal method of the object, passing the optional hint PreferredType.

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

Section 8.12.8describes the [[DefaultValue]]method. This method takes a "hint" as an argument, and the hint can be either String or Number. To simplify the matter by dispensing with some details, if the hint is String, then [[DefaultValue]]returns the value of toString()if it exists and returns a primitive value and otherwise returns the value of valueOf(). If the hint is Number, the priorities of toString()and valueOf()are reversed so that valueOf()is called first and its value returned if it's a primitive. Thus, whether [[DefaultValue]]returns the result of toString()or valueOf()depends on the specified PreferredType for the object and whether or not these functions return primitive values.

第 8.12.8 节描述了该[[DefaultValue]]方法。此方法将“提示”作为参数,提示可以是字符串或数字。为了通过省略一些细节来简化问题,如果提示是字符串,则[[DefaultValue]]返回 的值,toString()如果存在,则返回原始值,否则返回 的值valueOf()。如果提示是数字,则toString()和的优先级valueOf()颠倒,因此valueOf()首先调用它,如果它是原始类型,则返回其值。因此,是否[[DefaultValue]]返回的结果toString()valueOf()取决于指定PreferredType为对象,以及是否这些函数返回原始值。

The default valueOf()Object method just returns the object itself, which means that unless a class overrides the default method, valueOf()just returns the Object itself. This is the case for Array. [].valueOf()returns the object []itself. Since an Arrayobject is not a primitive, the [[DefaultValue]]hint is irrelevant: the return value for an array will be the value of toString().

默认的valueOf()Object 方法只返回对象本身,这意味着除非类覆盖默认方法,否则valueOf()只返回 Object 本身。对于Array. [].valueOf()返回对象[]本身。由于Array对象不是原始对象,因此[[DefaultValue]]提示无关紧要:数组的返回值将是 的值toString()

To quote David Flanagan's JavaScript: The Definitive Guide, which, by the way, is a superb book that should be everyone's first place to get answers to these types of questions:

引用David Flanagan 的JavaScript: The Definitive Guide,顺便说一句,这是一本很棒的书,应该是每个人获得这些类型问题答案的第一个地方:

The details of this object-to-number conversion explain why an empty array converts to the number 0 and why an array with a single element may also convert to a number. Arrays inherit the default valueOf() method that returns an object rather than a primitive value, so array-to-number conversion relies on the toString() method. Empty arrays convert to the empty string. And the empty string converts to the number 0. An array with a single element converts to the same string that that one element does. If an array contains a single number, that number is converted to a string, and then back to a number.

这个对象到数字转换的细节解释了为什么空数组转换为数字 0 以及为什么具有单个元素的数组也可以转换为数字。数组继承了默认的 valueOf() 方法,该方法返回对象而不是原始值,因此数组到数字的转换依赖于 toString() 方法。空数组转换为空字符串。空字符串将转换为数字 0。具有单个元素的数组将转换为与该元素相同的字符串。如果数组包含单个数字,则该数字将转换为字符串,然后再转换为数字。

The second type of answer to the "why" question, other than "because the spec says", gives some explanation for why the behavior makes sense from the design perspective. On this issue I can only speculate. First, how would one convert an array to a number? The only sensible possibility I can think of would be to convert an empty array to 0 and any non-empty array to 1. But as Wayne's answer revealed, an empty array will get converted to 0 for many types of comparisons anyway. Beyond this, it's hard to think of a sensible primitive return value for Array.valueOf(). So one could argue that it just makes more sense to have Array.valueOf()be the default and return the Array itself, leading toString()to be the result used by ToPrimitive. It just makes more sense to convert an Array to a string, rather than a number.

对“为什么”问题的第二种回答,除了“因为规范说”之外,从设计的角度解释了为什么这种行为是有意义的。在这个问题上,我只能推测。首先,如何将数组转换为数字?我能想到的唯一合理的可能性是将空数组转换为 0,将任何非空数组转换为 1。但正如韦恩的回答所揭示的那样,无论如何,对于许多类型的比较,空数组都会被转换为 0。除此之外,很难为 Array.valueOf() 想到一个合理的原始返回值。因此,有人可能会争辩说,Array.valueOf()使用默认值并返回 Array 本身更有意义,从而toString()导致 ToPrimitive 使用的结果。将 Array 转换为字符串而不是数字更有意义。

Moreover, as hinted by the Flanagan quote, this design decision does enable certain types of beneficial behaviors. For instance:

此外,正如弗拉纳根引述所暗示的那样,这种设计决策确实可以实现某些类型的有益行为。例如:

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

This behavior allows you to compare a single-element array to numbers and get the expected result.

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

回答by Tom Jiang

console.log('-- types: undefined, boolean, number, string, object --');
console.log(typeof undefined);  // undefined
console.log(typeof null);       // object
console.log(typeof NaN);        // number
console.log(typeof false);      // boolean
console.log(typeof 0);          // number
console.log(typeof "");         // string
console.log(typeof []);         // object
console.log(typeof {});         // object

console.log('-- Different values: NotExist, Falsy, NaN, [], {} --');
console.log('-- 1. NotExist values: undefined, null have same value --');
console.log(undefined == null); // true

console.log('-- 2. Falsy values: false, 0, "" have same value --');
console.log(false == 0);        // true
console.log(false == "");       // true
console.log(0 == "");           // true

console.log('-- 3. !NotExist, !Falsy, and !NaN return true --');
console.log(!undefined);        // true
console.log(!null);             // true

console.log(!false);            // true
console.log(!"");               // true
console.log(!0);                // true

console.log(!NaN);              // true

console.log('-- 4. [] is not falsy, but [] == false because [].toString() returns "" --');
console.log(false == []);       // true
console.log([].toString());     // ""

console.log(![]);               // false

console.log('-- 5. {} is not falsy, and {} != false, because {}.toString() returns "[object Object]" --');
console.log(false == {});       // false
console.log({}.toString());     // [object Object]

console.log(!{});               // false

console.log('-- Comparing --');
console.log('-- 1. string will be converted to number or NaN when comparing with a number, and "" will be converted to 0 --');
console.log(12 < "2");          // false
console.log("12" < "2");        // true
console.log("" < 2);            // true

console.log('-- 2. NaN can not be compared with any value, even if NaN itself, always return false --');
console.log(NaN == NaN);        // false

console.log(NaN == null);       // false
console.log(NaN == undefined);  // false
console.log(0 <= NaN);          // false
console.log(0 >= NaN);          // false
console.log(undefined <= NaN);  // false
console.log(undefined >= NaN);  // false
console.log(null <= NaN);       // false
console.log(null >= NaN);       // false

console.log(2 <= "2a");         // false, since "2a" is converted to NaN
console.log(2 >= "2a");         // false, since "2a" is converted to NaN

console.log('-- 3. undefined can only == null and == undefined, and can not do any other comparing even if <= undefined --');
console.log(undefined == null);         // true
console.log(undefined == undefined);    // true

console.log(undefined == "");           // false
console.log(undefined == false);        // false
console.log(undefined <= undefined);    // false
console.log(undefined <= null);         // false
console.log(undefined >= null);         // false
console.log(0 <= undefined);            // false
console.log(0 >= undefined);            // false

console.log('-- 4. null will be converted to "" when <, >, <=, >= comparing --');
console.log(12 <= null);        // false
console.log(12 >= null);        // true
console.log("12" <= null);      // false
console.log("12" >= null);      // true

console.log(0 == null);         // false
console.log("" == null);        // false

console.log('-- 5. object, including {}, [], will be call toString() when comparing --');
console.log(12 < {});           // false, since {}.toString() is "[object Object]", and then converted to NaN
console.log(12 > {});           // false, since {}.toString() is "[object Object]", and then converted to NaN
console.log("[a" < {});         // true, since {}.toString() is "[object Object]"
console.log("[a" > {});         // false, since {}.toString() is "[object Object]"
console.log(12 < []);           // false, since {}.toString() is "", and then converted to 0
console.log(12 > []);           // true, since {}.toString() is "", and then converted to 0
console.log("[a" < []);         // false, since {}.toString() is ""
console.log("[a" > []);         // true, since {}.toString() is ""

console.log('-- 6. According to 4 and 5, we can get below weird result: --');
console.log(null < []);         // false
console.log(null > []);         // false
console.log(null == []);        // false
console.log(null <= []);        // true
console.log(null >= []);        // true

回答by Thomson

In if (arr), it is always evaluated (ToBoolean) to true if arr is an object because all objects in JavaScript are truthy. (null is not an object!)

在 if (arr) 中,如果 arr 是一个对象,它总是被评估 (ToBoolean) 为 true ,因为JavaScript 中的所有对象都是 true。(null 不是对象!)

[] == falseis evaluated in iterative approach. At first, if one side of ==is primitive and the other is object, it converts object to primitive at first, then converts both sides to Number if both sides are not string(string comparison is used if both sides are strings). So the comparison is iterated like, [] == false-> '' == false-> 0 == 0-> true.

[] == false以迭代方法进行评估。首先,如果一边==是primitive,一边是object,先把object转换成primitive,如果两边都不是,就把两边都转换成Number(如果两边都是string字符串,就用字符串比较)。所以比较是迭代的,[] == false-> '' == false-> 0 == 0-> true

回答by yqbk

Example:

例子:

const array = []
const boolValueOfArray = !!array // true

It happens because

它发生是因为

ToNumber(ToPrimitive([])) == ToNumber(false)  
  1. []is empty Arrayobject → ToPrimitive([])→ "" → ToNumber("")0
  2. ToNumber(false)→ 0
  3. 0 == 0 → true
  1. []是空Array对象 → ToPrimitive([])→ "" → ToNumber("")0
  2. ToNumber(false)→ 0
  3. 0 == 0 → 真

回答by AliveXhd

You can empty a JavaScript Array by referencing it to a new array, using list = []or deleting the elements of the currently referenced array list.length = 0.

您可以通过将 JavaScript 数组引用到新数组、使用list = []或删除当前引用数组的元素来清空 JavaScript数组list.length = 0

Source: JavaScript Empty Array

来源:JavaScript 空数组

回答by Aldee

An array with elements (regardless if 0, false or another empty array), always resolves to trueusing Abstract Equality Comparison ==.

包含元素的数组(无论是 0、false 还是另一个空数组),始终解析为true使用 Abstract Equality Comparison ==

1. [] == false; // true, because an empty array has nothing to be truthy about
2. [2] == false; // false because it has at least 1 item
3. [false] == false; // also false because false is still an item
4. [[]] == false; // false, empty array is still an item

But using a Strict Equality Comparison ===, you are attempting to evaluate the variable's content as well as its data type that is why:

但是使用严格相等比较===,您正在尝试评估变量的内容及其数据类型,这就是为什么:

1. [] === false; // false, because an array (regardless of empty or not) is not strictly comparable to boolean `false`
2. [] === true; // false, same as above, cannot strictly compare [] to boolean `true`
3. [[]] === false; // true, because see #1

回答by domoarigato

None of the above helped me, when trying to use the knockout.js mapping plugin, perhaps since an "empty array" isn't really empty.

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

I ended up using: data-bind="if: arr().length"which did the trick.

我最终使用了:data-bind="if: arr().length"它成功了。

This is specific to knockout, not the OP's question, but maybe it will help someone else browsing here in a similar situation.

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