Please consider the below code:
function func1(a, b) {
let args = arguments;
console.log(args);
return function() {
for (let i in args) {
console.log(args[i], a, b)
args[i] += (a + b);
console.log("|")
console.log(args[i], a, b);
console.log("end")
}
}
}
func1(2, 4)();
This give the below output
2 2 4
|
8 8 4
end
4 8 4
|
16 8 16
end
How does the value of a, b change here?
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
function func1(a, b) {
let args = arguments;
console.log(args);
return function () {
for (let i in args) // it runs 2 times
{
console.log(args[i], a, b)
args[i] += (a + b);
// first time args[0] (this is the reference to 'a') set to 2+2+4 = 8
// second time args[1] (it is the reference to b) set to 4+8+4 = 16
console.log("|")
console.log(args[i], a, b);
console.log("end")
}
}}func1(2, 4)();
args[0] refers to a and args[0] refers to b
because args is a object that is stored is somewhere else in browser/node environment
refer how reference acts in js using this video