You Probably Don’t Need to Use Switch Statements in JavaScript

You Probably Don’t Need to Use Switch Statements in JavaScript

No switch, no complex code blocks

Switch is convenient: given an expression, we can check whether it matches a bunch of other expressions in a case clause. Consider the following example:

const name = "Juliana";

switch (name) {
  case "Juliana":
    console.log("She's Juliana");
    break;
  case "Tom":
    console.log("She's not Juliana");
    break;
}

When name is "Juliana", we print a message and immediately break out of the block. When inside a switch function, you can omit break by using return directly in the case block.

When there are no matches, the default option can be used:

const name = "Kris";

switch (name) {
  case "Juliana":
    console.log("She's Juliana");
    break;
  case "Tom":
    console.log("She's not Juliana");
    break;
  default:
    console.log("Sorry, no match");
}

Switch is also used heavily in Redux reducers (although Redux Toolkit simplifies the boilerplate a bit) to avoid having lots of if s. Consider the following example:

const LOGIN_SUCCESS = "LOGIN_SUCCESS";
const LOGIN_FAILED = "LOGIN_FAILED";

const authState = {
  token: "",
  error: "",
};

function authReducer(state = authState, action) {
  switch (action.type) {
    case LOGIN_SUCCESS:
      return { ...state, token: action.payload };
    case LOGIN_FAILED:
      return { ...state, error: action.payload };
    default:
      return state;
  }
}

Is there anything wrong with this? Hardly. But is there a better alternative?

Inspiration from Python

This Tweet from Telmo caught my attention. He shows two styles of "switch", one of which is very close to the pattern in Python.

Python doesn't have a switch, which gives us a better alternative. First let's port the code from JavaScript to Python:

LOGIN_SUCCESS = "LOGIN_SUCCESS"
LOGIN_FAILED = "LOGIN_FAILED"

auth_state = {"token": "", "error": ""}


def auth_reducer(state=auth_state, action={}):
    mapping = {
        LOGIN_SUCCESS: {**state, "token": action["payload"]},
        LOGIN_FAILED: {**state, "error": action["payload"]},
    }

    return mapping.get(action["type"], state)

In Python, we can use a dictionary to simulate switch. dict.get() can be used to represent the default statement of a switch.

When accessing a non-existent key, Python will trigger a KeyError error:

>>> my_dict = {

"name": "John",

"city": "Rome",

"age": 44

}

>>> my_dict["not_here"]

# Output: KeyError: 'not_here'

The .get() method is a safer approach because it will not raise an error and you can specify a default value for a non-existent key:

>>> my_dict = {

"name": "John",

"city": "Rome",

"age": 44

}

>>> my_dict.get("not_here", "not found")

# Output: 'not found'

Therefore, this line in Python:

return mapping.get(action["type"], state)

The equivalent in JavaScript is:

function authReducer(state = authState, action) {
  ...
    default:
      return state;
  ...
}

Use dictionary to replace switch

Consider the previous example again:

const LOGIN_SUCCESS = "LOGIN_SUCCESS";
const LOGIN_FAILED = "LOGIN_FAILED";

const authState = {
  token: "",
  error: "",
};

function authReducer(state = authState, action) {
  switch (action.type) {
    case LOGIN_SUCCESS:
      return { ...state, token: action.payload };
    case LOGIN_FAILED:
      return { ...state, error: action.payload };
    default:
      return state;
  }
}

Without using switch we can do this:

function authReducer(state = authState, action) {
  const mapping = {
    [LOGIN_SUCCESS]: { ...state, token: action.payload },
    [LOGIN_FAILED]: { ...state, error: action.payload }
  };

  return mapping[action.type] || state;
}

Here we use computed properties in ES6. Here, the properties of mapping are calculated on the fly based on two constants: LOGIN_SUCCESS and LOGIN_FAILED.
The value corresponding to the attribute is object destructuring, which comes from ES9 (ECMAScript 2018).

const mapping = {
  [LOGIN_SUCCESS]: { ...state, token: action.payload },
  [LOGIN_FAILED]: { ...state, error: action.payload }
}

What do you think of this approach? It may have some limitations for switches, but it may be a better solution for reducers.

But how does this code perform?

How is the performance?

The performance of switch is better than that of dictionary. We can test this using the following example:

console.time("sample");
for (let i = 0; i < 2000000; i++) {
  const nextState = authReducer(authState, {
    type: LOGIN_SUCCESS,
    payload: "some_token"
  });
}
console.timeEnd("sample");

Measure them about ten times,

for t in {1..10}; do node switch.js >> switch.txt; done

for t in {1..10}; do node map.js >> map.txt; done

The above is the details of why you may not need to use the switch statement in JavaScript. For more information about JavaScript switch statements, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • Summary of the use of three for loop statements in JavaScript (for, for...in, for...of)
  • Detailed explanation of common for loop in JavaScript statements
  • Summary of optimization techniques for conditional statements in JavaScript
  • How to run js statements in python
  • An article to help you understand JavaScript-statements

<<:  A brief discussion on Mysql specified order sorting query

>>:  Mysql5.6.36 script compilation, installation and initialization tutorial

Recommend

Detailed explanation of Vuex overall case

Table of contents 1. Introduction 2. Advantages 3...

About the location of the H1 tag in XHTML

There has been a lot of discussion about H1 recent...

Solution to the problem that Docker container cannot access Jupyter

In this project, the Docker container is used to ...

React implements double slider cross sliding

This article shares the specific code for React t...

JS version of the picture magnifying glass effect

This article shares the specific code of JS to ac...

How to inherit CSS line-height

How is Line-height inherited?Write a specific val...

How to rename the table in MySQL and what to pay attention to

Table of contents 1. Rename table method 2. Notes...

Analysis of the Linux input subsystem framework principle

Input subsystem framework The linux input subsyst...

Vue template compilation details

Table of contents 1. parse 1.1 Rules for intercep...

Detailed graphic and text instructions for installing MySQL 5.7.20 on Mac OS

Installing MySQL 5.7 from TAR.GZ on Mac OS X Comp...

JavaScript to achieve digital clock effects

This article example shares the specific code for...

The difference between docker run and start

The difference between run and start in docker Do...

How to use Vue3 asynchronous data loading component suspense

Table of contents Preface Creating Components Sum...

Ubuntu terminal multi-window split screen Terminator

1. Installation The biggest feature of Terminator...