How Clean Code Practices Supercharge Your JavaScript Projects

This article explores the importance of clean code in JavaScript, presenting the 3R software design principles, naming conventions, function design, component best practices, and practical refactorings with before‑and‑after code examples to help developers write more readable, reusable, and maintainable frontend code.

ELab Team
ELab Team
ELab Team
How Clean Code Practices Supercharge Your JavaScript Projects

Why Clean Code Matters

Clean code reduces bugs, eases maintenance, improves team collaboration, and makes the codebase more pleasant to work with.

Software quality is proportional to code cleanliness — Robert C. Martin

The 3R Software Design Principles

Readable, reusable, and refactorable code.

Naming Conventions

Use meaningful and readable variable names

👎 const yyyymmdstr = moment().format("YYYY/MM/DD");

👍 const currentDate = moment().format("YYYY/MM/DD");

Use meaningful variables instead of array indexes

👎 const address = "One Infinite Loop, Cupertino 95014";
const cityZipCodeRegex = /^[^,\]+[\s]+(.+?)\s*(\d{5})?$/;
saveCityZipCode(
  address.match(cityZipCodeRegex)[1],
  address.match(cityZipCodeRegex)[2]
);

👍 const address = "One Infinite Loop, Cupertino 95014";
const cityZipCodeRegex = /^[^,\]+[\s]+(.+?)\s*(\d{5})?$/;
const [_, city, zipCode] = address.match(cityZipCodeRegex) || [];
saveCityZipCode(city, zipCode);

Keep variable names concise

👎 const Car = {
  carMake: "Honda",
  carModel: "Accord",
  carColor: "Blue"
};
function paintCar(car, color) {
  car.carColor = color;
}

👍 const Car = {
  make: "Honda",
  model: "Accord",
  color: "Blue"
};
function paintCar(car, color) {
  car.color = color;
}

Eliminate magic numbers

👎 setTimeout(blastOff, 86400000);

👍 const MILLISECONDS_PER_DAY = 60 * 60 * 24 * 1000; // 86400000
setTimeout(blastOff, MILLISECONDS_PER_DAY);

Use default parameters instead of short‑circuit operators

👎 function createMicrobrewery(name) {
  const breweryName = name || "Hipster Brew Co.";
  // ...
}

👍 function createMicrobrewery(name = "Hipster Brew Co.") {
  // ...
}

Function Design

One function should do one thing

👎 function emailClients(clients) {
  clients.forEach(client => {
    const clientRecord = database.lookup(client);
    if (clientRecord.isActive()) {
      email(client);
    }
  });
}

👍 function emailActiveClients(clients) {
  clients.filter(isActiveClient).forEach(email);
}
function isActiveClient(client) {
  const clientRecord = database.lookup(client);
  return clientRecord.isActive();
}

Limit function parameters to two; use object destructuring when many are needed

👎 function createMenu(title, body, buttonText, cancellable) {
  // ...
}
createMenu("Foo", "Bar", "Baz", true);

👍 function createMenu({ title, body, buttonText, cancellable }) {
  // ...
}
createMenu({
  title: "Foo",
  body: "Bar",
  buttonText: "Baz",
  cancellable: true
});

Function names should reflect their purpose

👎 function addToDate(date, month) {
  // ...
}
addToDate(date, 1);

👍 function addMonthToDate(month, date) {
  // ...
}
addMonthToDate(1, date);

Keep abstraction levels shallow; split overly complex functions

👎 function parseBetterJSAlternative(code) {
  const REGEXES = [/* ... */];
  const statements = code.split(" ");
  const tokens = [];
  REGEXES.forEach(REGEX => {
    statements.forEach(statement => {
      // ...
    });
  });
  const ast = [];
  tokens.forEach(token => {
    // lex...
  });
  ast.forEach(node => {
    // parse...
  });
}

👍 function parseBetterJSAlternative(code) {
  const tokens = tokenize(code);
  const syntaxTree = parse(tokens);
  syntaxTree.forEach(node => {
    // parse...
  });
}
function tokenize(code) {
  const REGEXES = [/* ... */];
  const statements = code.split(" ");
  const tokens = [];
  REGEXES.forEach(REGEX => {
    statements.forEach(statement => {
      tokens.push(/* ... */);
    });
  });
  return tokens;
}
function parse(tokens) {
  const syntaxTree = [];
  tokens.forEach(token => {
    syntaxTree.push(/* ... */);
  });
  return syntaxTree;
}

Reduce duplicate code

👎 function showDeveloperList(developers) {
  developers.forEach(developer => {
    const expectedSalary = developer.calculateExpectedSalary();
    const experience = developer.getExperience();
    const githubLink = developer.getGithubLink();
    const data = { expectedSalary, experience, githubLink };
    render(data);
  });
}
function showManagerList(managers) {
  managers.forEach(manager => {
    const expectedSalary = manager.calculateExpectedSalary();
    const experience = manager.getExperience();
    const portfolio = manager.getMBAProjects();
    const data = { expectedSalary, experience, portfolio };
    render(data);
  });
}

👍 function showEmployeeList(employees) {
  employees.forEach(employee => {
    const expectedSalary = employee.calculateExpectedSalary();
    const experience = employee.getExperience();
    const data = { expectedSalary, experience };
    switch (employee.type) {
      case "manager":
        data.portfolio = employee.getMBAProjects();
        break;
      case "developer":
        data.githubLink = employee.getGithubLink();
        break;
    }
    render(data);
  });
}

Prefer pure functions over imperative ones

👎 const programmerOutput = [
  { name: "Uncle Bobby", linesOfCode: 500 },
  { name: "Suzie Q", linesOfCode: 1500 },
  { name: "Jimmy Gosling", linesOfCode: 150 },
  { name: "Gracie Hopper", linesOfCode: 1000 }
];
let totalOutput = 0;
for (let i = 0; i < programmerOutput.length; i++) {
  totalOutput += programmerOutput[i].linesOfCode;
}

👍 const programmerOutput = [
  { name: "Uncle Bobby", linesOfCode: 500 },
  { name: "Suzie Q", linesOfCode: 1500 },
  { name: "Jimmy Gosling", linesOfCode: 150 },
  { name: "Gracie Hopper", linesOfCode: 1000 }
];
const totalOutput = programmerOutput.reduce((totalLines, output) => totalLines + output.linesOfCode, 0);

Avoid side effects in functions

👎 const addItemToCart = (cart, item) => {
  cart.push({ item, date: Date.now() });
};

👍 const addItemToCart = (cart, item) => {
  return [...cart, { item, date: Date.now() }];
};

Don’t over‑optimize premature loops

👎 for (let i = 0, len = list.length; i < len; i++) {
  // ...
}

👍 for (let i = 0; i < list.length; i++) {
  // ...
}

Comments

Comments are an apology, not a requirement

👎 function hashIt(data) {
  // The hash
  let hash = 0;
  // Length of string
  const length = data.length;
  // Loop through every character in data
  for (let i = 0; i < length; i++) {
    // Get character code.
    const char = data.charCodeAt(i);
    // Make the hash
    hash = (hash << 5) - hash + char;
    // Convert to 32-bit integer
    hash &= hash;
  }
}

👍 function hashIt(data) {
  let hash = 0;
  const length = data.length;
  for (let i = 0; i < length; i++) {
    const char = data.charCodeAt(i);
    hash = (hash << 5) - hash + char;
    // Convert to 32-bit integer
    hash &= hash;
  }
}

Avoid putting version‑control notes in comments

👎 /**
 * 2016-12-20: Removed monads, didn't understand them (RM)
 * 2016-10-01: Improved using special monads (JP)
 * 2016-02-03: Removed type-checking (LI)
 * 2015-03-14: Added combine with type-checking (JR)
 */
function combine(a, b) {
  return a + b;
}

👍 function combine(a, b) {
  return a + b;
}

Components

Prefer functional components

👎 class Counter extends React.Component {
  state = { counter: 0 };
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState({ counter: this.state.counter + 1 });
  }
  render() {
    return (
      <div>
        <p>counter: {this.state.counter}</p>
        <button onClick={this.handleClick}>Increment</button>
      </div>
    );
  }
}

👍 function Counter() {
  const [counter, setCounter] = useState(0);
  const handleClick = () => setCounter(counter + 1);
  return (
    <div>
      <p>counter: {counter}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
}

Extract logic from components

👎 export default function Component() {
  const [value, setValue] = useState('');
  function isValid() {
    // ...
  }
  return (
    <>
      <input value={value} onChange={e => setValue(e.target.value)} onBlur={validateInput} />
      <button onClick={() => { if (isValid) { /* ... */ } }}>Submit</button>
    </>
  );
}

👍 function isValid(value) {
  // ...
}
export default function Component() {
  const [value, setValue] = useState('');
  return (
    <>
      <input value={value} onChange={e => setValue(e.target.value)} onBlur={validateInput} />
      <button onClick={() => { if (isValid(value)) { /* ... */ } }}>Submit</button>
    </>
  );
}

Keep component length short

👎 function Filters({ onFilterClick }) {
  return (
    <>
      <p>Book Genres</p>
      <ul>
        <li><div onClick={() => onFilterClick('fiction')}>Fiction</div></li>
        <li><div onClick={() => onFilterClick('classics')}>Classics</div></li>
        <li><div onClick={() => onFilterClick('fantasy')}>Fantasy</div></li>
        <li><div onClick={() => onFilterClick('romance')}>Romance</div></li>
      </ul>
    </>
  );
}

👍 const GENRES = [
  { identifier: 'fiction', name: 'Fiction' },
  { identifier: 'classics', name: 'Classics' },
  { identifier: 'fantasy', name: 'Fantasy' },
  { identifier: 'romance', name: 'Romance' }
];
function Filters({ onFilterClick }) {
  return (
    <>
      <p>Book Genres</p>
      <ul>
        {GENRES.map(genre => (
          <li>
            <div onClick={() => onFilterClick(genre.identifier)}>{genre.name}</div>
          </li>
        ))}
      </ul>
    </>
  );
}

Avoid defining components inside other components

👎 function Component() {
  function renderHeader() {
    return <header>...</header>;
  }
  return <div>{renderHeader()}</div>;
}

👍 import Header from '@modules/common/components/Header';
function Component() {
  return (
    <div>
      <Header />
    </div>
  );
}

Optimize props usage

👎 function Component() {
  const count = 0;
  return <div>{count && <h1>Messages: {count}</h1>}</div>;
}

👍 function Component() {
  const count = 0;
  return <div>{count ? <h1>Messages: {count}</h1> : null}</div>;
}

Other Recommendations

Place each component in its own folder

// 👎 All component files together
components/
  Header.jsx
  Header.scss
  Header.test.jsx
  Footer.jsx
  Footer.scss
  Footer.test.jsx

// 👍 Separate folders per component
components/
  Header/
    index.js
    Header.jsx
    Header.scss
    Header.test.jsx
  Footer/
    index.js
    Footer.jsx
    Footer.scss
    Footer.test.jsx

Prefer absolute import paths

Using absolute paths reduces the number of changes needed when moving files and makes dependencies clearer.

(End of article)

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

best practicesrefactoringclean code
ELab Team
Written by

ELab Team

Sharing fresh technical insights

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.