Skip to main content

Front end practice: Top 25+ Javascript code best practices for development


 In a previous article, I covered front-end best practices in CSS/SCSS. This article will share the basic javascript best practices for development

Frontend development in JavaScript involves creating user interfaces and handling the presentation layer of web applications. Here are some best practices to follow, along with examples, to ensure a clean and maintainable codebase:

1.Modularization: Break down your code into smaller, reusable modules. This enhances code readability and makes it easier to manage dependencies.

Example:

// users.js (module)
export function getUsers() {
  // Fetch users from the API or data source
}

// main.js (entry point)
import { getUsers } from './users.js';

getUsers();

2.Use const and let: Prefer const for variables that won't be reassigned and let for variables that will change.

Example:

const PI = 3.14159;
let count = 0;

count = 10; // Valid
PI = 3; // Error

3.Avoid global variables: Minimize the use of global variables to prevent polluting the global scope and potential conflicts.

Example:

// Avoid this
let globalVar = 'I am global';

function someFunction() {
  // ...
}

// Use this instead
(function() {
  let localVar = 'I am local';

  function someFunction() {
    // ...
  }
})();

4.Use arrow functions: Arrow functions provide concise syntax and maintain the lexical this value, reducing the need for bind().

Example:

// Regular function
function add(a, b) {
  return a + b;
}

// Arrow function
const add = (a, b) => a + b;

5.Avoid polluting the global namespace: Encapsulate your code within a module or an IIFE (Immediately Invoked Function Expression) to avoid global namespace pollution.

Example:

// Instead of
function myFunction() {
  // ...
}

// Use this
(function() {
  function myFunction() {
    // ...
  }

  // Call the function or attach it to the desired scope
  myFunction();
})();

6.Use modern ES6+ features: Embrace ES6+ features like destructuring, spread syntax, and template literals to write more concise and expressive code.

Example:

// Destructuring
const { firstName, lastName } = user;

// Spread syntax
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combinedArray = [...arr1, ...arr2];

// Template literals
const name = `My name is ${firstName} ${lastName}.`;

7.Avoid inline styles and use CSS classes: Keep your HTML and JavaScript code separated. Use CSS classes for styling, and manipulate classes with JavaScript instead of inline styles.

Example:

<!-- Bad: Inline style -->
<button style="background-color: #007bff; color: #fff;">Click Me</button>

<!-- Good: CSS class -->
<button class="primary-btn">Click Me</button>

8.Optimize DOM manipulation: Minimize direct DOM manipulation and use efficient approaches like template literals or libraries/frameworks that efficiently update the DOM.

Example (using template literals):

const data = ['Item 1', 'Item 2', 'Item 3'];

function renderList(data) {
  const list = document.getElementById('list');
  list.innerHTML = '';

  data.forEach(item => {
    const listItem = document.createElement('li');
    listItem.textContent = item;
    list.appendChild(listItem);
  });
}

renderList(data);

9.Use event delegation: Attach event listeners to parent elements and utilize event delegation for handling events on dynamically added elements.

Example:

<ul id="list">
  <!-- List items will be added dynamically -->
</ul>
document.getElementById('list').addEventListener('click', event => {
  if (event.target.nodeName === 'LI') {
    // Handle click on list item
    console.log(event.target.textContent);
  }
});

10.Optimize asset loading: Minimize the number of HTTP requests and use techniques like bundling and minification to optimize asset loading.

11.Error Handling: Always handle errors gracefully to avoid unexpected application crashes and improve user experience.

Example:

function divide(a, b) {
  if (b === 0) {
    throw new Error('Division by zero is not allowed.');
  }
  return a / b;
}

try {
  const result = divide(10, 0);
  console.log(result);
} catch (error) {
  console.error('An error occurred:', error.message);
}

12.Use Promises or Async/Await for Asynchronous Operations: Avoid using nested callbacks for asynchronous operations and use Promises or Async/Await to improve code readability and maintainability.

Example using Promises:

function fetchData() {
  return fetch('https://api.example.com/data')
    .then(response => response.json());
}

fetchData()
  .then(data => console.log(data))
  .catch(error => console.error('Error fetching data:', error));

Example using Async/Await:

async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    return data;
  } catch (error) {
    throw new Error('Error fetching data:', error);
  }
}

(async () => {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (error) {
    console.error(error.message);
  }
})();

13.Avoid Manipulating the DOM Directly in Loops: When performing DOM manipulation inside loops, batch the changes or use DocumentFragment to minimize layout thrashing and improve performance.

Example:

// Bad: Directly manipulating DOM in a loop
const list = document.getElementById('list');
for (let i = 0; i < 1000; i++) {
  const listItem = document.createElement('li');
  listItem.textContent = `Item ${i}`;
  list.appendChild(listItem);
}

// Good: Batch changes using DocumentFragment
const list = document.getElementById('list');
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
  const listItem = document.createElement('li');
  listItem.textContent = `Item ${i}`;
  fragment.appendChild(listItem);
}
list.appendChild(fragment);

14.Use Debouncing or Throttling for Event Handlers: When handling events that could trigger frequently (e.g., resize or scroll), use debouncing or throttling techniques to reduce the number of function calls and improve performance.

Example using Lodash's debounce function:

import { debounce } from 'lodash';

function handleResize() {
  // Code to handle window resize
}

window.addEventListener('resize', debounce(handleResize, 200));

15.Use Semantic HTML: Write meaningful and semantic HTML to improve accessibility, SEO, and maintainability.

Example:

<!-- Bad: Using generic divs -->
<div class="header">
  <div class="title">My Website</div>
</div>

<!-- Good: Using semantic HTML -->
<header>
  <h1>My Website</h1>
</header>

16.Use ES6 Modules instead of Global Scripts: Organize your JavaScript code into separate modules, and use ES6 import and export statements instead of loading multiple scripts in the global scope.

Example (Module 1):

// module1.js
export function foo() {
  // ...
}

Example (Module 2):

// module2.js
export function bar() {
  // ...
}

Example (Main Script):

// main.js
import { foo } from './module1.js';
import { bar } from './module2.js';

foo();
bar();

17.Avoid Nested Ternary Operators: While ternary operators can be useful for concise expressions, nesting them can lead to code that is hard to read and understand. Instead, use regular if-else statements for complex conditions.

Example:

// Bad: Nested ternary
const result = condition1
  ? value1
  : condition2
  ? value2
  : condition3
  ? value3
  : defaultValue;

// Good: Using if-else
let result;
if (condition1) {
  result = value1;
} else if (condition2) {
  result = value2;
} else if (condition3) {
  result = value3;
} else {
  result = defaultValue;
}

18.Avoid Excessive Comments: Comments are essential for code documentation, but avoid over-commenting self-explanatory code. Let the code speak for itself whenever possible.

Example:

// Bad: Excessive comments
function add(a, b) {
  // This function adds two numbers and returns the result
  return a + b; // Return the sum
}

// Good: Minimal, self-explanatory comments
function add(a, b) {
  return a + b;
}

19.Use Object Shorthand: When creating object literals with properties that have the same name as the variables, use object shorthand for cleaner code.

Example:

// Bad: Repetitive code
const firstName = 'John';
const lastName = 'Doe';

const user = {
  firstName: firstName,
  lastName: lastName,
};

// Good: Object shorthand
const firstName = 'John';
const lastName = 'Doe';

const user = {
  firstName,
  lastName,
};

20.Avoid Using eval(): The eval() function can execute arbitrary code and is generally considered unsafe and bad practice. Find alternative solutions to achieve your goals without using eval().

Example (Bad - Avoid eval()):

const expression = '10 + 20';
const result = eval(expression);
console.log(result); // Output: 30

21.Use textContent Instead of innerHTML: When working with plain text content, prefer textContent over innerHTML to prevent potential security vulnerabilities (e.g., cross-site scripting - XSS).

Example:

// Bad: Using innerHTML for plain text
const text = '<script>alert("Hello XSS!");</script>';
const element = document.getElementById('myElement');
element.innerHTML = text; // This will execute the script

// Good: Using textContent
const text = '<script>alert("Hello XSS!");</script>';
const element = document.getElementById('myElement');
element.textContent = text; // Treats it as plain text, no script execution

22.Use addEventListener Instead of Inline Event Handlers: Instead of using inline event handlers in HTML (e.g., onclick="myFunction()"), use addEventListener in JavaScript for better separation of concerns.

Example (Bad - Inline Event Handler):

<button onclick="handleClick()">Click Me</button>
function handleClick() {
  // Event handling logic
}

Example (Good - addEventListener):

<button id="myButton">Click Me</button>
document.getElementById('myButton').addEventListener('click', handleClick);

function handleClick() {
  // Event handling logic
}

23.Use const and let instead of var: Prefer const and let over var for variable declarations to avoid hoisting and block-scoping issues.

Example:

// Bad: Using var
var x = 10;

// Good: Using const or let
const x = 10;
let y = 20;

24.Use map()filter(), and reduce() for Array Operations: Utilize higher-order array methods like map()filter(), and reduce() to perform operations on arrays in a functional and declarative manner.

Example using map():

const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map(num => num * 2);
console.log(doubledNumbers); // Output: [2, 4, 6, 8, 10]

Example using filter():

const numbers = [1, 2, 3, 4, 5];
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // Output: [2, 4]

Example using reduce():

const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum); // Output: 15

25.Avoid document.write(): The use of document.write() can cause unexpected behavior and overwrite the entire document if used after the page has finished loading. Use DOM manipulation methods instead.

Example (Bad - Avoid document.write()):

document.write('<h1>Hello World</h1>');

26.Use classList for Managing CSS Classes: Instead of directly manipulating the className, use classList methods like add()remove()toggle(), and contains() to manage CSS classes.

Example:

<div id="myDiv" class="container">Content</div>
const element = document.getElementById('myDiv');

// Adding a class
element.classList.add('highlight');

// Removing a class
element.classList.remove('container');

// Checking if a class exists
if (element.classList.contains('highlight')) {
  // Do something
}

// Toggling a class
element.classList.toggle('active');

27.Use requestAnimationFrame() for Smooth Animations: When creating animations, use requestAnimationFrame() to ensure smooth and efficient animations that run at the optimal frame rate.

Example:

function animate() {
  // Code to update the animation

  requestAnimationFrame(animate);
}

// Start the animation
animate();

28.Avoid Synchronous AJAX Requests: Avoid using synchronous XMLHttpRequest (XHR) as it can block the main thread, causing a poor user experience. Instead, use asynchronous requests with Promises, async/await, or callbacks.

Example using Promises:

function fetchData() {
  return fetch('https://api.example.com/data')
    .then(response => response.json());
}

fetchData()
  .then(data => console.log(data))
  .catch(error => console.error('Error fetching data:', error));

Example using async/await:

async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    return data;
  } catch (error) {
    throw new Error('Error fetching data:', error);
  }
}

(async () => {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (error) {
    console.error(error.message);
  }
})();


Thanks for reading :)


Comments

Popular posts from this blog

Advanced Next.js URL handling with URLSearchParams

  Video Tutorial Introduction In Next.js, you can work with URL query parameters using the next/router module, which provides a way to access and manipulate the query string parameters of the current URL. Query parameters are typically used to pass data from one page to another or to filter content on a page. Here's how you can work with URL query parameters in Next.js: Step 1: Setup next.js project. if you want more about it  read the article Step 2: Import URL search params in your file  page.tsx|jsx . import { useSearchParams } from 'next/navigation' Step 3: Use the useSearchParams hook into the file like below: export default function Example() { const searchParams = useSearchParams()!; } Step 4: Accessing query params value into your component: export default function Example() { let term; const searchParams = useSearchParams()!; // Set updated value to the term if(searchParams?.has('term')) { term = searchParams.get('term'); } retur...

Tailwind CSS theming system detected theme, manual mode dark and light theme with NextJS

Introduction?   In the ever-evolving world of web development, user experience plays a crucial role in determining the success of a website or web application. One aspect of user experience that has gained significant attention in recent years is the choice between light and dark themes. Users prefer different themes based on their surroundings and personal preferences, and as a developer, you can enhance their experience by offering theme options that adapt to their needs. In this guide, we'll explore how to implement system preferences, light and dark themes in a Next.js application with the help of Tailwind CSS. Why Implement System Preferences and Theme Switching? The choice between light and dark themes is not just about aesthetics; it also impacts usability and accessibility. Users often prefer a dark theme in low-light environments, while a light theme is preferred during the day. To provide a seamless user experience, you can implement system preferences to detect the user...

Building Cross-Platform PWAs with Next.js: From Web to Mobile

A Progressive Web App (PWA) is a type of web application that offers a user experience similar to that of a traditional native mobile app or desktop application. PWAs are designed to be fast, reliable, and engaging, and they combine the best features of web and mobile apps. Here are some key characteristics and features of PWAs: Progressive Enhancement:  PWAs are designed to work on any platform, whether it's a desktop, mobile device, or tablet. They provide a consistent user experience across various screen sizes and resolutions. Offline Capabilities:  One of the defining features of PWAs is their ability to work offline or in low-network conditions. They achieve this through the use of service workers, which cache essential resources and enable the app to function even when there's no internet connection. Responsive Design:  PWAs are built with responsive web design in mind, ensuring that the user interface adapts to different screen sizes and orientations, providing a ...

Step-by-Step Guide to Setting up Next.js with Tailwind CSS

Introduction Web development frameworks and libraries are evolving at a rapid pace, and staying up-to-date with the latest technologies is essential for building modern, responsive web applications. Next.js and Tailwind CSS are two popular tools that have gained significant attention in the web development community. Next.js is a powerful React framework for building server-rendered web applications, while Tailwind CSS is a utility-first CSS framework that simplifies styling and offers a responsive design system. why next.js use over react? Next.js is a framework built on top of React that provides a number of features and benefits that make it a good choice for building modern web applications. Some of the reasons why you might choose to use Next.js over React include: Server-side rendering (SSR). Next.js provides built-in support for SSR, which can improve the performance and SEO of your application. Static site generation (SSG). Next.js can also generate static HTML pages that can...

No code API development for front end engineer/web developer

  Creating an API without writing any code might seem impossible, but there are ways to streamline the process and simplify development using low-code or no-code tools. In this blog post, we will explore various approaches to develop APIs without extensive coding. Code demo URL Thanks for reading!