空数组为真,但也等于假。
Var arr = []; console.log(数组:,arr); if (arr) console.log("这是真的!"); if (arr == false) console.log("这是假的!"); 如果(arr & & arr = = false) console.log(“……什么? ?”);
我猜这是由于由等式运算符进行的隐式转换。
有人能解释一下幕后发生了什么吗?
空数组为真,但也等于假。
Var arr = []; console.log(数组:,arr); if (arr) console.log("这是真的!"); if (arr == false) console.log("这是假的!"); 如果(arr & & arr = = false) console.log(“……什么? ?”);
我猜这是由于由等式运算符进行的隐式转换。
有人能解释一下幕后发生了什么吗?
当前回答
为了补充Wayne的回答,并尝试解释为什么ToPrimitive([])返回“”,值得考虑“why”问题的两种可能类型的答案。第一种回答是:“因为规范说JavaScript就是这样运行的。”在ES5规范第9.1节中,将ToPrimitive的结果描述为对象的默认值:
通过调用对象的[[DefaultValue]]内部方法来检索对象的默认值,并传递可选提示PreferredType。
Section 8.12.8 describes 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.
默认的valueOf() Object方法只返回对象本身,这意味着除非类重写默认方法,否则valueOf()只返回对象本身。这就是Array的情况。[]. valueof()返回对象[]本身。由于Array对象不是原语,[[DefaultValue]]提示是不相关的:数组的返回值将是toString()的值。
引用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.
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.
此外,正如Flanagan所暗示的那样,这种设计决策确实能够实现某些类型的有益行为。例如:
var a = [17], b = 17, c=1;
console.log(a==b); // <= true
console.log(a==c); // <= false
此行为允许您将单个元素数组与数字进行比较,并获得预期的结果。
其他回答
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
为了补充Wayne的回答,并尝试解释为什么ToPrimitive([])返回“”,值得考虑“why”问题的两种可能类型的答案。第一种回答是:“因为规范说JavaScript就是这样运行的。”在ES5规范第9.1节中,将ToPrimitive的结果描述为对象的默认值:
通过调用对象的[[DefaultValue]]内部方法来检索对象的默认值,并传递可选提示PreferredType。
Section 8.12.8 describes 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.
默认的valueOf() Object方法只返回对象本身,这意味着除非类重写默认方法,否则valueOf()只返回对象本身。这就是Array的情况。[]. valueof()返回对象[]本身。由于Array对象不是原语,[[DefaultValue]]提示是不相关的:数组的返回值将是toString()的值。
引用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.
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.
此外,正如Flanagan所暗示的那样,这种设计决策确实能够实现某些类型的有益行为。例如:
var a = [17], b = 17, c=1;
console.log(a==b); // <= true
console.log(a==c); // <= false
此行为允许您将单个元素数组与数字进行比较,并获得预期的结果。
当我尝试使用knockout.js映射插件时,上述方法都没有帮助我,也许是因为“空数组”并不是真的空。
我最终使用:data-bind="if: arr()。长度”,这就成功了。
这是专门针对knockout的,不是OP的问题,但也许它会帮助其他在类似情况下浏览这里的人。
你可以通过引用一个新的数组来清空JavaScript数组,使用list =[]或者删除当前引用数组列表中的元素。Length = 0。
来源:JavaScript空数组
关于台词:
if (arr == false) console.log("It's false!");
下面这些也许会有所帮助:
console.log(0 == false) // true
console.log([] == 0) // true
console.log([] == "") // true
我相信发生的是布尔值false被强制为0,以便与对象(左侧)进行比较。对象被强制转换为字符串(空字符串)。然后,空字符串也被强制转换为一个数字,即零。所以最后的比较结果是0 == 0,这是正确的。
编辑:请参阅规范的这一部分,以了解具体的工作原理。
从规则1开始,事情是这样的:
1. 如果“Type(x)”和“Type(y)”不一致,执行步骤14。
下一个适用的规则是第19条:
19. 如果Type(y)是Boolean,返回比较的结果x == 当时(y)。
ToNumber(false)的结果是0,所以我们现在有:
[] == 0
同样,规则1告诉我们跳转到步骤14,但实际应用的下一步是#21:
21. 如果类型(x)是对象,类型(y)是字符串或数字,则返回 对比结果 ToPrimitive (x) = = y。
ToPrimitive([])的结果是空字符串,所以我们现在有:
"" == 0
同样,规则1告诉我们跳转到步骤14,但实际应用的下一步是#17:
17. 如果Type(x)是String且Type(y)是Number,则返回 number (x)== y。
ToNumber("")的结果是0,剩下的是:
0 == 0
现在,两个值具有相同的类型,因此步骤从#1继续到#7,即:
7. 如果x与y的数值相同,则返回true。
因此,我们返回true。
简而言之:
ToNumber(ToPrimitive([])) == ToNumber(false)