1

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?

3
  • I'm surprised that I'm not finding a good original question to link this to. Commented Feb 6, 2022 at 13:40
  • 2
    The value of each arg is being reassigned here args[i] += (a+b); Commented Feb 6, 2022 at 13:40
  • Given the i values to be 0 and 1, args[0] is a and when you do args[0] += (a+b) is as good as a += (a+b) and same happens with b when i is 1. Commented Feb 6, 2022 at 13:48

2 Answers 2

5

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

Sign up to request clarification or add additional context in comments.

4 Comments

So even though if we clone the arguments, it still have live link to its clone?
@GokulGokzz - Nothing in the code you've shown clones the arguments object. let args = arguments; just points args at the object, it doesn't copy it.
On deep clone, let args = JSON.parse(JSON.stringify(arguments)), the values of a,b , remains the same.
@GokulGokzz - Right, but A) You don't need a deep clone, just a shallow copy (const args = [...arguments]; or const args = Array.prototype.slice.call(arguments);); and B) Never clone anything using a round-trip through JSON, it's lossy and slow. :-) Use a deep cloning function instead.
1
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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.