我一直在尝试实现一种方法,该方法将数组和索引作为输入,将给定数组的最后一个元素复制到给定索引处的条目中,然后 chop 最后一个元素(即设置数组短一个)。
这是我作为此任务的建议给出的功能:
function swapWithLastAndRemove(array, index) {
array[index] = array.pop();
}
然后我测试了这个函数以确保它适用于任何给定的索引:
for (let index = 0; index < 5; index++) {
var array = [0, 1, 2, 3, 4];
swapWithLastAndRemove(array, index);
console.log(array);
}
而且我发现它对除最后一个索引以外的所有索引都能正常工作:
[ 4, 1, 2, 3 ]
[ 0, 4, 2, 3 ]
[ 0, 1, 4, 3 ]
[ 0, 1, 2, 4 ]
[ 0, 1, 2, 3, 4 ]
换句话说,对于最后一个元素,它将它从数组中弹出,然后将其重写到数组中。
令我印象深刻的是这一行:
array[index] = array.pop();
在最后一个元素上执行时相当于此行:
array[array.length - 1] = array.pop();
不可能导致 array
的内容等于 [ 0, 1, 2, 3, 4 ]
。
在我看来,这里有两个选项:
- 语句
array.pop()
在表达式array.length - 1
被求值之前执行 - 语句
array.pop()
在表达式array.length - 1
求值后执行
在第一种情况下,数组的内容会发生如下变化:
[ 0, 1, 2, 3, 4 ]//初始状态
[ 0, 1, 2, 3 ]//弹出 4 之后
[ 0, 1, 2, 4 ]//赋值后
在第二种情况下,它应该会触发某种内存访问冲突,因为会尝试写入数组中的第 5 个条目 (array[4]
),当数组的长度只有 4 个条目。
我知道 NodeJS 可以应用一些内存管理方案,以某种方式允许它在没有“数组索引越界”异常的情况下完成,但我仍然不明白为什么它会让这个操作“逃脱”它”,此外,为什么结果是这样。
行 array[array.length - 1] = array.pop()
可能是未定义的行为吗?
JavaScript 中是否存在未定义的行为?
最佳答案
The second option: The statement
array.pop()
is executed after the expressionarray.length - 1
is evaluated
这确实发生了。 JS 评估总是从左到右。它计算 array.length - 1
到数组的索引 4
,然后从数组中弹出最后一个元素,然后将该元素分配给索引 4。
In the second case, it should have triggered some sort of memory-access violation, because there would be an attempt to write into the 5th entry in the array (
array[4]
), when the length of the array is only 4 entries.
没有,JS中没有内存访问冲突。它只是再次创建一个新属性,并相应地更改数组的长度。这与代码发生的情况相同
const array = [0, 1, 2, 3, 4];
const element = array.pop();
console.log(JSON.stringify(array)); // [0,1,2,3]
array[4] = element;
console.log(JSON.stringify(array)); // [0,1,2,3,4]
类似地,填充数组使用相同的特性:
const array = [];
for (let i=0; i<5; i++)
array[i] = i; // no memory access violation
console.log(array.length); // 5
关于javascript - 'array[array.length - 1] = array.pop()' 会产生未定义的行为吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59068472/