DEV Community

Zell Liew ๐Ÿค—
Zell Liew ๐Ÿค—

Posted on • Edited on • Originally published at zellwk.com

Why you shouldn't reassign values in JavaScript

In JavaScript, you can reassign values to variables you declared with let or var.

I used to reassign values a lot. But as I got better with JavaScript, I realized you shouldn't reassign values if you can. This is because:

  1. You may change external state by accident when you reassign values
  2. You create more complex code when you reassign values

You may change external state by accident when you reassign values

When you assign a new value to a variable, you write the variable name, followed by =, followed by your new value.

// Declaring a variable
let name = 'Zell'

// Reassigning a variable
name = 'Vincy'
Enter fullscreen mode Exit fullscreen mode

It seems okay to reassign values at first glance, but it isn't. The problem arises when you look at scopes.

Let's say you have a variable called name in the global context.

Let's also say you created a function called sayName. sayName logs the argument you passed into it. But before you log the argument, you change the name variable.

let name = 'Zell'

function sayName (arg) {
  name = arg
  console.log(name)
}
Enter fullscreen mode Exit fullscreen mode

When you call sayName, you change the value of name forever. It changed the state outside of the function.

sayName('Vincy') // Vincy
console.log(name) // Vincy
Enter fullscreen mode Exit fullscreen mode

Now, you may think that this example sounds stupid, and you'll never write silly code like this.

The question is, can you guarantee that you'll never make this mistake, even when you're in the thick of things?

I can't.

Make it a habit not to reassign variables.

I recommend always create variables with the const keyword. This is because variables created with a const keyword cannot be reassigned. You'll get an error if you try to assign a new value to them.

const name = 'Zell'

function sayName (arg) {
  name = arg
  console.log(name)
}

sayName('Vincy') // TypeError: invalid assignment to const `name'
Enter fullscreen mode Exit fullscreen mode

You create complex code when you reassign values

Imagine a colleague of your changes her hairstyle every day. She comes into the office with:

  1. Bangs on Monday
  2. Braids on Tuesday
  3. Short hair on Wednesday
  4. Long hair on Thursday
  5. Bright pink hair on Friday

It'll be hard for you to recognize her.

When you create a variable with let, your brain knows the variable is going to change. It exerts more energy to keep track of the changes down the road.

Let's go through an example and you'll see how this works.

let hair

if (today === 'Monday') {
  hair = 'bangs'
} else {
  hair = 'something else'
}
Enter fullscreen mode Exit fullscreen mode

Here, your brain goes:

  1. There's a variable called hair.
  2. The value of hair is going to change later. I don't know its value now. (This is uncomfortable).
  3. Later...
  4. today is Monday.
  5. Hair is going to be bangs

Now compare this thought process with one where you use ternary operators.

const hair = today === 'Monday'
  ? 'bangs'
  : 'something else'
Enter fullscreen mode Exit fullscreen mode

Here, your brain goes:

  1. There's a variable called hair.
  2. today is Monday.
  3. Hair is going to be bangs.

There's no "wait and see" moments with the ternary operator code. Your brain does lesser work since doesn't need to "wait and see".

It's kind of like deciding what you're going to have for lunch. You won't waste energy thinking about what to eat if you've decided beforehand.

Working with many branches

Ternary operators only work if you have simple if/else statements. What if you need more branches?

let hair

if (today === 'Monday') {
  hair = 'bangs'
} else if (today === 'Tuesday') {
  hair = 'braids'
} else if (today === 'Wednesday') {
  hair = 'short hair'
} else if (today === 'Thursday') {
  hair = 'long hair'
} else if (today === 'Friday') {
  hair = 'bright pink hair'
}
Enter fullscreen mode Exit fullscreen mode

The best way to handle many if/else statements (or even a switch) statement is to contain the if/else logic in a function.

Here's a start (where we simply wrap a function around the above code):

function getHairType (today) {
  let hair

  if (today === 'Monday') {
    hair = 'bangs'
  } else if (today === 'Tuesday') {
    hair = 'braids'
  } else if (today === 'Wednesday') {
    hair = 'short hair'
  } else if (today === 'Thursday') {
    hair = 'long hair'
  } else if (today === 'Friday') {
    hair = 'bright pink hair'
  }

  return hair
}
Enter fullscreen mode Exit fullscreen mode

When you call getHairType, you don't really care how it works. All you care about is the value you'll get back from getHairType. This makes it easier for you to understand how your code executes.

// Using the function
const hair = getHairType('Wednesday') // short hair
Enter fullscreen mode Exit fullscreen mode

The next step will be to improve getHairType. Here, you can use an early return.

An early return means you return a value before the function completes execution. When you do this, you don't even need to create a hair variable. You can return the value of hair directly.

function getHairType (today) {
  if (today === 'Monday') return 'bangs'
  if (today === 'Tuesday') return 'braids'
  if (today === 'Wednesday') return 'short hair'
  if (today === 'Thursday') return 'long hair'
  if (today === 'Friday') return 'bright pink hair'
}
Enter fullscreen mode Exit fullscreen mode

Much easier to read now, isn't it?

Wrapping up

You want to avoid reassigning values to variables because:

  1. You may change external state by accident when you reassign values
  2. You create more complex code when you reassign values

Instead of reassigning values, try using ternary operators and early returns. They can make your code terser and easier to read.

If this lesson has helped you, might enjoy Learn JavaScript, where you'll learn how to build anything you want from scratch. Enrollment for Learn JavaScript opens in July 2018 (in three weeks!).


Thanks for reading. This article was originally posted on my blog. Sign up for my newsletter if you want more articles to help you become a better frontend developer.

Top comments (14)

Collapse
 
jonrandy profile image
Jon Randy ๐ŸŽ–๏ธ • Edited

Even easier to read?

function getHairType (today) {
  return {
    Monday: 'bangs',
    Tuesday: 'braids',
    Wednesday: 'short hair',
    Thursday: 'long hair',
    Friday: 'bright pink hair'
  } [today];
}

@miguelqueiroz - I was thinking the same. Admittedly the function wrapper above is pointless

Collapse
 
miguelqueiroz profile image
Miguel Queiroz

That's my point. But its funny to know your hair is sort of undefined for Saturday or sundays ehe..

Collapse
 
jonrandy profile image
Jon Randy ๐ŸŽ–๏ธ

Bad hair days! ๐Ÿ˜

Thread Thread
 
zellwk profile image
Zell Liew ๐Ÿค—

Ooh! You're completely right there. I should have came up with a better example ๐Ÿ˜….

Collapse
 
dallgoot profile image
dallgoot
function getHairType (today) {
  switch(today.toLowerCase()){
    case "monday":    return 'bangs';
    case "tuesday":   return 'braids';
    case "wednesday": return 'short hair';
    case "thursday":  return 'long hair';
    case "friday":    return 'bright pink hair';
    default:
        //default value or throw "only workdays allowed for 'today'"
  }
}

or to allow rapid visualisation of constants:

const MONDAY_HAIRTYPE = 'bangs';
// ... const for each day
const DEFAULT_HAIRTYPE = MONDAY_HAIRTYPE; 

let dayHairType = today.toUpperCase()+"_HAIRTYPE"; 
hair = dayHairType in this ? this[dayHairType] : DEFAULT_HAIRTYPE;

no undefined, no function call cost

Collapse
 
shalvah profile image
Shalvah • Edited

Good article @zellwk . Another useful habit to cultivate is not allowing your functions to modify anything that wasn't created within it (or at the least, passed in as an argument). That way you won't have to worry too much about mistakenly reassigning something else.

Collapse
 
zellwk profile image
Zell Liew ๐Ÿค—

Yup. Pure functions FTW.

Collapse
 
squgeim profile image
Shreya Dahal

This is what I tell people when they argue against using const ("it's not really immutable"). When using const is the default, we naturally think in ways that result in better code.

Most functions have a structure like this:

let var1;
// ... do stuff to settle on the value for var1

let var2;
// ... do stuff to settle on the value for var2

// ... use var1 and var2 to produce the result.

When we are allowed to reassign, these "concerns" easily get intertwined and a clear separation is not visible. It also becomes harder to extract out meaningful function out for reuse.

With no reassignment the code looks more like:

const var1 = condition ? value1 : value2;

const var2 = (() => {
  // Do stuff to settle on a value of var2

  return value2;
})();

There is a clear separation of concern and it is easier to refactor.

Collapse
 
adriannull profile image
adriannull

WTH ? I strongly believe this promotes stupidity amongst programmers. It's verry natural for a function to be able to access global variables, both for read and write operations. It's your job as a programmer to fully understand the function you're trying to change, which variables are local and which are global. Not to mention that you could have naming convensions like "all global variables start with g_". And on top of that, it's a good practice to comment your code, for both you and others. Simply placing a comment like "// here we set value X in global variable Y" makes things crystal clear.

If we would use each variable only once, we would need to work with far more variables and our code would be alot bigger and alot messier. Not to mention we would increase memory size.

A simple example i can think of, often found in my codes, is something like this (pseudocode here, i work mostly in PHP):

var arrData = DATABASE->SomeQuery(1);
do something with arrData, from above query only,
  usually iterating through each row and calculate something,
  put final data in, let s say, variables A, B, C;

arrData = DATABASE->SomeQuery(2);
do something with arrData, from above query only,
  usually iterating through each row and calculate something,
  put final data in, let s say, variables D, E, F;

... and so on

Basically, if i would need 5 different queries, returning large amounts of data, but i only need that data for a verry short amount of time, why on earth would i want to create separate variables to load my memory more than needed ?

Collapse
 
neradev profile image
Moritz Schramm

Optimization can often lead to code that is harder to read, test and maintain. You are right saying that is the task of an programmer to understand the code. But I would not like to work in such code. Moreover in times of huge in-memory-databases, memory is not as expensive as programmers maintaining and extending the code.

Collapse
 
jonrandy profile image
Jon Randy ๐ŸŽ–๏ธ

Just noticed you may want to rewrite this bit:

I recommend always create variables with the const keyword. This is because variables created with a const keyword cannot be reassigned. You'll get an error if you try to assign a new value to them.

The const keyword creates constants, not variables.

Collapse
 
shalvah profile image
Shalvah • Edited

They're not really "constants" in a strict sense because, even though you can't reassign, you can modify the referenced value (if it's an object). For instance:

const x = {a: 1};

// this will fail
x = {a: 2};

// but this will pass
x.a = 2;
Collapse
 
miguelqueiroz profile image
Miguel Queiroz

I would totally not use a function but instead an object like:

Hair={"monday":"bangs",
"Tuesday":"braids"};
and so on...

return Hair[today];

Collapse
 
esamcoding profile image
esam a gndelee

the real problem is not reassigning values, the real problem is global scoped variables.

javascript is really nasty. it was not chosen because it is the best.