All Articles

JS: Don’t Reassign Closure Variables!

I had a serious “gotcha” moment while writing a GraphQL article and felt completely lost.

Consider this code:

always = (value) => () => value;
give10 = always(10);

give10(); // 10

always takes a value and returns a function that always returns value. Simple, right?

This is only possible because JavaScript allows functions to share their variable scope with any functions they return. So even though always executed, value isn’t garbage-collected because the returned function, give10, is referencing it as a closure variable.

This works with objects/arrays too:

nums = [1, 2, 3];
giveNums = always(nums);

giveNums(); // [1, 2, 3]

You can even mutate nums down the road and be just fine:

nums.pop();
giveNums(); // [1, 2]

But things get weird when you reassign it…

nums = [4, 5, 6];
giveNums(); // [1, 2]

Reassigning a variable doesn’t change it across closures.

(╯°□°)╯︵ ┻━┻

You might reassign a variable being used in hundreds of closure scopes and get tons of errors (silent ones, if you’re unlucky), and you’ll have no idea why.

We all knew this applies to primitives (numbers, strings, booleans), because they are passed by value. They’re copied and stored in a new memory address.

myNum = 10;
getMyNum = always(myNum);

++myNum; // 11
getMyNum(); // 10

Arrays and objects aren’t copied, however, they’re passed by reference. So the function’s just told, “Hey, myNum is at this address, go get it.”

But reassigning a variable creates a new reference, no matter what.

Consider this code:

bobo = { name: 'Bobo' };
getBobo = always(bobo);

bobo === getBobo(); // true

That returns true because getBobo references bobo’s address.

Mutating bobo doesn’t affect that relationship:

bobo.name = 'Mutant-Bobo';
bobo === getBobo(); // true

But reassigning bobo stores him somewhere else, leaving our closures hanging.

bobo = { name: 'New-Bobo' };
getBobo(); // { name: 'Mutant-Bobo' }

Old bobo’s still in memory, but he’s only accessible through getBobo’s closure, because no one else is referencing him.

This is all based on my own testing, and I’m further researching this enlightening “gotcha”. If anything’s missing/incorrect, please leave a comment! ❤️

Be careful, my friends. Until next time!