In loose mode,¹ the arguments
pseudo-array has a live link to the formal parameters of a function. Here's a simpler example:
function example(a) {
console.log("before, a = " + a);
++arguments[0];
console.log("after, a = " + a);
}
example(1);
As you can see, ++arguments[0]
modified the value of a
.
This spooky link is removed in strict mode, which should be used by all new code (explicitly, or by using modules):
"use strict";
function example(a) {
console.log("before, a = " + a);
++arguments[0];
console.log("after, a = " + a);
}
example(1);
In a comment, you've asked:
So even though if we clone the arguments, it still have live link to its clone?
Nothing in the code in the question clones the arguments
object. let args = arguments;
just points args
at the object, it doesn't copy it. You start out with:
+−−−−−−−−−−−−−−−−−−−−−−−−−−+
arguments:−−−−−>| (arguments object) |
+−−−−−−−−−−−−−−−−−−−−−−−−−−+
| (spooky link to a, b) |
+−−−−−−−−−−−−−−−−−−−−−−−−−−+
Then let args = arguments;
just does this:
arguments:−−+
|
| +−−−−−−−−−−−−−−−−−−−−−−−−−−+
+−−>| (arguments object) |
| +−−−−−−−−−−−−−−−−−−−−−−−−−−+
| | (spooky link to a, b) |
args:−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−−−−−+
It's still the same object.
If you copy it (just a shallow copy is fine), then you can modify the copy without affecting a
and b
:
let args = [...arguments]; // Or `= Array.prototype.slice.call(arguments);`
Then you get:
+−−−−−−−−−−−−−−−−−−−−−−−−−−+
arguments:−−−−−>| (arguments object) |
+−−−−−−−−−−−−−−−−−−−−−−−−−−+
| (spooky link to a, b) |
+−−−−−−−−−−−−−−−−−−−−−−−−−−+
+−−−−−−−−−−−−−−−−−−−−−−−−−−+
argss:−−−−−−−−−>| (array) |
+−−−−−−−−−−−−−−−−−−−−−−−−−−+
| 0: value copied from `a` |
| 1: value copied from `b` |
+−−−−−−−−−−−−−−−−−−−−−−−−−−+
...and changes to args
don't show in a
and b
.
¹ loose mode is often, sadly, called "sloppy" mode