Why does ++[[]][+[]] == 1?

来源:互联网 发布:nginx 支持pathinfo 编辑:程序博客网 时间:2024/04/27 03:23

Answer by John Resig:

To start, you need to know that JavaScript has type coercion. Numbers can become strings, strings can become numbers, and arrays can become strings.

Thus, for example: [] in a string context becomes "". "" in a number context becomes 0. Thus if we were to do: "" - 1 we'd get the number -1. Additionally if we were to do [] - 1 we'd get -1. ++ is also able to coerce a string into a number.

If ++ is able to turn a string into a number then you're probably wondering why they just don't do ++[] and be done with it (to get 1, that is). The problem is that ++ is attempting to assign that resulting value back somewhere and since [] doesn't exist anywhere yet (it's temporary) it throws an error instead.

We could do something like this:

    var a = [];    ++a; // 1
But we can't actually assign the result to a variable because we can't use alphanumeric characters. So what's another way in which we can assign the results to a variable? We can stick it into an array.
    var a = [ [] ];    ++a[ 0 ]; // 1
This also works:
    ++[ [] ][ 0 ];
Now, we can't use 0 because it's alphanumeric so we swap 0 for +[] (+ turns the string "" into the number 0, [] turns into the string ""). Thus we get the final result:
    ++[ [] ][ +[] ]

Followed by kangax

The explanation of why ++[] throws error is actually incorrect. This has nothing to do with "existence" of [] (I'm not even sure what existence could mean here). Rather, it's the way ++ operator works.

++ requires its operand to evaluate to a _reference_, not a _value_. If operand evaluates to a value, a ReferenceError is thrown (well, actually it is internal PutValue method that throws error, but that's irrelevant here). Now, if we were to pass reference to ++ operator, it would "work" as expected. E.g.:

++({ x: 1 }).x;

In this case, `({ x: 1 }).x` is a reference, it evaluates to 1, and is then increased by 1 to produce 2 as a resulting value.

When you said "this also works" with `++[ [] ][ 0 ]` example, what happened is that `[ [] ][ 0 ]` evaluated to a reference too, and returned a value of array (inner one). The fact that something like ++[[]][0] "works" should already hint at the fact that "existence" of an object is a bogus reasoning ;)

So what we really need to understand here (besides type coercion) is the notion of references. Literals, for example, always evaluate to values: 1, "foo", true, ({ x: 1 }), and [] are all values. Expressions involving property accessors, on the other hand — foo.bar, [1][0], ({ x: 1 }).x — are all references.

Understanding this distinction can also help explain other aspects of Javascript, such as, say, simple assignments, where left hand operand is constrained by the same rules as ++ operator; it should always evaluate to a reference:

1 = 1; // ReferenceError, LHS operand is not a reference

null = 1; // ReferenceError, LHS operand is not a reference

// but

({ x: 1 }).x = 1; // works as expected, LHS operand is a reference

x = 1; // works as expected, LHS operand is a reference

FWIW, it is the same internal PutValue method that's invoked by `=` operator, and is why assignment to non-reference values result in an error.

Then by John Resig

"This has nothing to do with 'existence' of [] (I'm not even sure what existence could mean here)."

Ah sorry, I was referring to the fact that the array was already created and within another object that we were referencing. But yeah, thanks for your more-in-depth explanation!




原创粉丝点击