Javascript apparent madness [duplicate]

大城市里の小女人 提交于 2019-12-18 13:17:23

问题


Possible Duplicate:
Conflicting boolean values of an empty JavaScript array

What is the rationale behind the fact that

[ ([] == false), ([] ? 1 : 2) ]

returns [true, 1]?

In other words an empty list is logically true in a boolean context, but is equal to false.

I know that using === solves the issue, but what is the explanation behind this apparently totally illogical choice?

In other words is this considered a mistake in the language, something unintentional that just happened and that cannot be fixed because it's too late or really in the design of the language someone thought it was cool to have this kind of apparent madness that I'm sure is quite confusing for many programmers?

The technical explanation of how this happens is at the same time amazing and scaring, I was however more interested in what is behind this design.

Edit

I accepted very detailed Nick Retallack explanation, even if it's only about the technical reasons of why []==false is true: surprisingly enough it happens is because [] converted to string is an empty string and the empty string numeric value is special cased to be 0 instead of the apparently more logical NaN. With an empty object for example the comparison ({}) == false returns false because the string representation of an empty object is not the empty string.

My curiosity still remains about all this being just unanticipated (and now unfortunately solidified in a standard).


回答1:


Let's get technical. I'll explain the logic with quotes from the ECMAScript Standard 262.

The expression [] ? 1 : 2 is very simple:

11.12 Conditional Operator ( ? : )

  • Let lref be the result of evaluating LogicalORExpression.
  • If ToBoolean(GetValue(lref)) is true, then
    • Let trueRef be the result of evaluating the first AssignmentExpression.
    • Return GetValue(trueRef).
  • Else
    • Let falseRef be the result of evaluating the second AssignmentExpression.
    • Return GetValue(falseRef)

9.2 ToBoolean

  • Undefined: false
  • Null: false
  • Boolean: The result equals the input argument (no conversion).
  • Number: The result is false if the argument is +0, 0, or NaN; otherwise the result is true.
  • String: The result is false if the argument is the empty String (its length is zero); otherwise the result is true.
  • Object: true

So it's true.


Now for the wild ride of what happens when you use the double equals operator. Perhaps this will help explain why you should never do this.

The behavior of == is explained in in section 11.9.3: The Abstract Equality Comparison Algorithm.

For x == y where x = [] and y = false, this happens:

11.9.3: The Abstract Equality Comparison Algorithm

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

9.3 ToNumber

The result is +0 if the argument is false.

Now we have [] == 0

11.9.3: The Abstract Equality Comparison Algorithm

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

9.1 ToPrimitive

Return a default value for the Object. The default value of an object is retrieved by calling the [[DefaultValue]] internal method of the object, passing the optional hint PreferredType. The behaviour of the [[DefaultValue]] internal method is defined by this specification for all native ECMAScript objects in 8.12.8.

8.12.8 DefaultValue:

When the [[DefaultValue]] internal method of O is called with no hint, then it behaves as if the hint were Number

  • Let valueOf be the result of calling the [[Get]] internal method of object O with argument "valueOf".
  • If IsCallable(valueOf) is true then,
    • Let val be the result of calling the [[Call]] internal method of valueOf, with O as the this value and an empty argument list.
    • If val is a primitive value, return val
  • Let toString be the result of calling the [[Get]] internal method of object O with argument "toString".
  • If IsCallable(toString) is true then,
    • Let str be the result of calling the [[Call]] internal method of toString, with O as the this value and an empty argument list.
    • If str is a primitive value, return str.

I assume this first attempts valueOf and then rejects it because the result is the same array you started with. It then calls toString on Array, which seems to be universally implemented as a comma separated list of its values. For empty arrays like this one, that results in empty string.

Now we have '' == 0

11.9.3: The Abstract Equality Comparison Algorithm

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

9.3.1 ToNumber Applied to the String Type

A StringNumericLiteral that is empty or contains only white space is converted to +0.

Now we have 0 == 0

11.9.3: The Abstract Equality Comparison Algorithm

If x is the same Number value as y, return true

Awesome. It's true. Pretty convoluted way of getting here though.




回答2:


The confusion here is around the definition of "falsy" in JavaScript, which (contrary to popular belief) isn't the same as == false.

Falsy actually refers to a value that has a boolean equivalent of false, not an expression whose result == false. The only Falsy values in JavaScript are: false, 0, "", null, undefined, and NaN. So any of those values -- or any expression that evalutes to one of those values (like in an if statment or using the ternary operator) -- is falsy.

Here's a table I put together of falsy/truthy values in JavaScript that should help explain this whole issue. http://jsfiddle.net/philipwalton/QjSYG/



来源:https://stackoverflow.com/questions/10555986/javascript-apparent-madness

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!