动态数组元素的求值顺序是否有保证?
Is the evaluation order of dynamic array elements guaranteed?
我试图找到一种简洁的方法将数组的最后一个元素移动到第一个位置,并提出了一个单行解决方案pop
ping 元素并散布到数组中:
arr1 = [arr1.pop(), ...arr1];
我的问题是:这里的评估顺序是否有保证,跨浏览器?
我问是因为如果 ...arr1
在 之前 arr1.pop()
求值,那么数组将在开头以相同元素的副本结束,并且结尾(例如 [1, 2, 3, 4, 5, 1]
)。
我知道在 Javascript 中,求值总是从左到右线性进行,这在表达式和函数参数列表中是有意义的。我找不到的是并发数组元素是否计入这种线性性质,或者是否有可能同时评估它们(或者它是否取决于标准的实现)。
语法概览一览:Array Initializer Syntax
(注意:在下文中,为了简洁起见,我从语法中排除了 Elision_opt,这说明连续的逗号或没有前面定义的元素的逗号允许空元素,
例如:[el1,,el2]=[el1,(empty),el2]
)
首先,根据12.2.5.2 Runtime Semantics: Evaluation:
[ arr1.pop(), ...arr1 ]
[ ElementList ]
12.2.5.1 Runtime Semantics: ArrayAccumulation:
arr1.pop() , ...arr1
ElementList: ElementList, SpreadElement
- Set nextIndex to the result of performing ArrayAccumulation for ElementList with arguments array and nextIndex.
[...]
- Return the result of performing ArrayAccumulation for SpreadElement with arguments array and nextIndex.
因此在第 1 步。ArrayAccumulation
必须在 arr1.pop()
上执行,然后才能计算 ...arr1
。您会注意到,在这种情况下,SpreadElement
的计算甚至取决于从第一部分调用 ArrayAccumulation
得出的 nextIndex
的值。并且语法评估以从左到右评估的方式递归,从右边的部分分支出来。
(这只是语法分析的一个特性。)
另请注意:
ElementList: ElementList, AssignmentExpression
和
ElementList: ElementList, ...AssignmentExpression
结构相同。
(注:以上已经是保证评价顺序的证明)
其余的评估如下:
arr1.pop()
ElementList: AssignmentExpression
- Let created be ! CreateDataPropertyOrThrow(array, ! ToString(nextIndex), initValue).
- Return nextIndex + 1.
因此 SpreadElement
接下来在 arr1
上调用 ArrayAccumulation
,参数数组插入了 arr1.pop()
的 return 值和 nextIndex + 1
SpreadElement ArrayAccumulation,大致总结一下,在arr1
(AssignmentExpression
)上得到一个迭代器,对其进行迭代,并:
d. Perform ! CreateDataPropertyOrThrow(array, ! ToString(nextIndex), nextValue).
在每个迭代值上。
我试图找到一种简洁的方法将数组的最后一个元素移动到第一个位置,并提出了一个单行解决方案pop
ping 元素并散布到数组中:
arr1 = [arr1.pop(), ...arr1];
我的问题是:这里的评估顺序是否有保证,跨浏览器?
我问是因为如果 ...arr1
在 之前 arr1.pop()
求值,那么数组将在开头以相同元素的副本结束,并且结尾(例如 [1, 2, 3, 4, 5, 1]
)。
我知道在 Javascript 中,求值总是从左到右线性进行,这在表达式和函数参数列表中是有意义的。我找不到的是并发数组元素是否计入这种线性性质,或者是否有可能同时评估它们(或者它是否取决于标准的实现)。
语法概览一览:Array Initializer Syntax
(注意:在下文中,为了简洁起见,我从语法中排除了 Elision_opt,这说明连续的逗号或没有前面定义的元素的逗号允许空元素,
例如:[el1,,el2]=[el1,(empty),el2]
)
首先,根据12.2.5.2 Runtime Semantics: Evaluation:
[ arr1.pop(), ...arr1 ]
[ ElementList ]
12.2.5.1 Runtime Semantics: ArrayAccumulation:
arr1.pop() , ...arr1
ElementList: ElementList, SpreadElement
- Set nextIndex to the result of performing ArrayAccumulation for ElementList with arguments array and nextIndex.
[...]
- Return the result of performing ArrayAccumulation for SpreadElement with arguments array and nextIndex.
因此在第 1 步。ArrayAccumulation
必须在 arr1.pop()
上执行,然后才能计算 ...arr1
。您会注意到,在这种情况下,SpreadElement
的计算甚至取决于从第一部分调用 ArrayAccumulation
得出的 nextIndex
的值。并且语法评估以从左到右评估的方式递归,从右边的部分分支出来。
(这只是语法分析的一个特性。)
另请注意:
ElementList: ElementList, AssignmentExpression
和
ElementList: ElementList, ...AssignmentExpression
结构相同。
(注:以上已经是保证评价顺序的证明)
其余的评估如下:
arr1.pop()
ElementList: AssignmentExpression
- Let created be ! CreateDataPropertyOrThrow(array, ! ToString(nextIndex), initValue).
- Return nextIndex + 1.
因此 SpreadElement
接下来在 arr1
上调用 ArrayAccumulation
,参数数组插入了 arr1.pop()
的 return 值和 nextIndex + 1
SpreadElement ArrayAccumulation,大致总结一下,在arr1
(AssignmentExpression
)上得到一个迭代器,对其进行迭代,并:
d. Perform ! CreateDataPropertyOrThrow(array, ! ToString(nextIndex), nextValue).
在每个迭代值上。