When arguments are mutable

I've found this weird behavior of the arguments inside a function while playing and experimenting with some code some days ago. Normally it would not be interesting since all the code we use is usually built-transpiled and put into strict mode, but my sandbox was not - and this is an exact case when omitting strict mode can cause weird side effects.

Arguments

Lets start with the famous arguments object found in almost* every function in JavaScript.

Quickly go over what you can and cannot do with arguments.

You can

  • access the passed arguments using a zero-based index
  • access its length
  • use it with the spread operator
  • completely overwrite it in non-strict mode
  • iterate over it using for-of
  • update values in it, using indexes
  • attach static methods and properties on it

You cannot

  • use array methods on it
  • add new items
  • remove items from it

Looks pretty clear, right? Now, let's get down the rabbit hole...

Tracking and mutating

Focus on our mutable arguments object right now. Take a look at this piece of code, and try to guess what is written to the console:

gist:84225415896af12d1be18d18db54d413#param_reassign.js

Just by looking at the code, we think it should log 2. But here comes the strange quirk, it will log "foo". If you don't believe me, try it out yourself.

What just happened?! Turns out there is a maintained relationship between the arguments of a function, and the arguments object, when certain conditions apply:

When a non-strict function does not contain rest, default, or destructured parameters, then the values in the arguments object do track the values of the arguments (and vice versa).

This works vice-versa, altering either the named argument or an entry in the arguments object, will track the changes to the other one:

gist:84225415896af12d1be18d18db54d413#arguments_relationship.js

Using strict mode, or working with rest, defaults or destructured arguments will prevent this weird behavior

gist:84225415896af12d1be18d18db54d413#arguments_relationship-strict_mode.js

Check out these examples as real code in this bin.

Quirks like this can cause side effects, and severe bugs later in your code, so be safe! The following tricks can help you, to keep your code sane:

  • use strict mode whenever possible, not just in your compiled, authored code
  • use ESLint, with rules like no-param-reassign

PS: this is totally different, when you assign an argument entry to a variable inside the function, like here

gist:84225415896af12d1be18d18db54d413#param_assignment.js