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

本文深入探讨了JavaScript中类型的强制转换机制,包括数字与字符串之间的相互转换、数组到字符串的转换等,并通过具体示例解释了如何利用这些特性来实现特定的操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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!




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值