我无法跟踪和理解 Java(和 Javascript)如何处理以下代码:
// Java
int i = 0;
int[] a = {10, 20, 30, 40, 50, 60};
a[++i] = a[i++] = a[++i] = ++i;
System.out.println(Arrays.toString(a));
// [10, 4, 30, 4, 50, 60]
let i = 0;
const a = [10, 20, 30, 40, 50, 60];
a[++i] = a[i++] = a[++i] = ++i;
console.log( JSON.stringify(a)); // [10, 4, 30, 4, 50, 60]
运行时,输出为
[10, 4, 30, 4, 50, 60]
。
我们甚至可以简化这个例子:
int i = 0;
int[] a = {10, 20};
a[i] = ++i;
System.out.println(Arrays.toString(a));
// [1, 20]
let i = 0;
const a = [10, 20];
a[i] = ++i;
console.log( JSON.stringify(a) ); // [1, 20]
我预计这会输出
[10, 1]
,因为右手边在前。但输出是[1, 20]
,但是如何呢?
我预计这会输出
,因为右手边在前[10, 1]
不,在两种语言中,首先评估
=
的左侧,然后是右侧。
参见15.26.1。当 LHS 是数组访问表达式时,来自 Java 规范的简单赋值运算符 = 关于
=
的求值顺序(我的重点):
如果左侧操作数是数组访问表达式(第 15.10.3 节), 可能用一对或多对括号括起来,然后:
首先,左侧操作数的数组引用子表达式 数组访问表达式被求值...
否则,左侧操作数数组的 索引子表达式 评估访问表达式。如果这个评估突然完成, 然后赋值表达式由于同样的原因突然完成 并且右侧操作数不会被求值,也不会发生赋值。
否则,计算右侧操作数。
ECMAScript 规范还具有用于首先在第 13.15.2 节中评估左侧的运行时语义:
如果 LeftHandSideExpression 既不是 ObjectLiteral 也不是 ArrayLiteral,那么
a.让 lref 为 ?评价 左手边表达式。