JavaScript Best Practices
Following best practices in JavaScript helps you write cleaner, more maintainable, and more efficient code. This guide covers essential practices that every JavaScript developer should follow.
Use Strict Mode
Always use strict mode by adding 'use strict';
at the beginning of your JavaScript files or functions. Strict mode helps catch common coding mistakes and "unsafe" actions.
'use strict';
// This will throw an error in strict mode
// because x is not declared
x = 10;
// This will also throw an error
// because delete cannot be used on a variable
let y = 20;
delete y;
Tip: When using ES6 modules or classes, strict mode is automatically enabled.
Variable Declarations
Use const and let, Avoid var
Use const
for values that won't change, and let
for values that will. Avoid using var
due to its function-scoping and hoisting behavior.
Bad Practice | Good Practice |
---|---|
|
|
Declare Variables at the Top
Declare variables at the top of their scope to make your code more readable and to avoid hoisting-related issues.
Good Practice:
function calculateArea(width, height) {
const area = width * height;
const perimeter = 2 * (width + height);
console.log(`Area: ${area}`);
console.log(`Perimeter: ${perimeter}`);
return { area, perimeter };
}
Function Best Practices
Function Declarations vs. Expressions
Prefer function declarations for top-level functions and arrow functions for callbacks and methods.
// Function declaration - hoisted and can be called before defined
function calculateArea(width, height) {
return width * height;
}
// Arrow function - concise and lexically binds 'this'
const calculatePerimeter = (width, height) => 2 * (width + height);
// Method in an object
const rectangle = {
width: 10,
height: 5,
getArea() {
return this.width * this.height;
}
};
Keep Functions Small and Focused
Each function should do one thing and do it well. This makes your code easier to test, debug, and maintain.
Bad Practice | Good Practice |
---|---|
|
|
Object and Array Best Practices
Use Object and Array Destructuring
Destructuring makes your code cleaner and more readable when working with objects and arrays.
// Object destructuring
const user = { name: 'John', age: 30, email: 'john@example.com' };
const { name, age, email } = user;
// With default values
const { name, age, role = 'User' } = user;
// Array destructuring
const coordinates = [10, 20, 30];
const [x, y, z] = coordinates;
// Skipping elements
const [first, , third] = coordinates;
// Function parameters
function displayUser({ name, age }) {
console.log(`${name} is ${age} years old`);
}
Use Spread and Rest Operators
Spread and rest operators make working with arrays and objects more concise.
// Spread operator with arrays
const numbers = [1, 2, 3];
const moreNumbers = [...numbers, 4, 5]; // [1, 2, 3, 4, 5]
// Spread operator with objects
const user = { name: 'John', age: 30 };
const userWithEmail = { ...user, email: 'john@example.com' };
// Rest operator in function parameters
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
// Rest operator in destructuring
const [first, ...rest] = [1, 2, 3, 4, 5];
Error Handling
Always handle errors properly to prevent your application from crashing and to provide better user experience.
// Using try-catch
try {
const data = JSON.parse(userInput);
processData(data);
} catch (error) {
console.error('Error processing data:', error.message);
// Show user-friendly error message
displayError('Sorry, there was a problem processing your request.');
}
// With async/await
async function fetchUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Error fetching user data:', error);
// Handle error appropriately
return null;
}
}
Warning: Never use empty catch blocks. Always handle or at least log the error.
Avoid Global Variables
Global variables can lead to naming conflicts and make your code harder to maintain. Use modules, closures, or objects to encapsulate your code.
Bad Practice | Good Practice |
---|---|
|
|
Use Modern JavaScript Features
Take advantage of modern JavaScript features to write cleaner, more expressive code.
// Template literals
const greeting = `Hello, ${userName}!`;
// Optional chaining
const city = user?.address?.city;
// Nullish coalescing
const role = user.role ?? 'User';
// Array methods
const activeUsers = users.filter(user => user.isActive);
const userNames = users.map(user => user.name);
const totalAge = users.reduce((sum, user) => sum + user.age, 0);
// Object methods
const hasAdmin = users.some(user => user.role === 'Admin');
const allAdults = users.every(user => user.age >= 18);
Performance Best Practices
Avoid Excessive DOM Manipulation
DOM operations are expensive. Minimize them by batching changes and using document fragments.
Bad Practice | Good Practice |
---|---|
|
|
Debounce and Throttle Event Handlers
Use debouncing and throttling for events that fire frequently, like scrolling, resizing, or typing.
// Debounce function
function debounce(func, delay) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), delay);
};
}
// Throttle function
function throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// Usage
const debouncedSearch = debounce(searchFunction, 300);
const throttledScroll = throttle(scrollHandler, 100);
searchInput.addEventListener('input', debouncedSearch);
window.addEventListener('scroll', throttledScroll);
Code Organization
Use Consistent Naming Conventions
Adopt a consistent naming convention for variables, functions, classes, and files.
// Variables and functions: camelCase
const firstName = 'John';
function calculateTotal() { }
// Classes: PascalCase
class UserProfile { }
// Constants: UPPER_CASE or camelCase
const MAX_USERS = 100;
const apiBaseUrl = 'https://api.example.com';
// Private properties/methods: _prefixed or #private (ES2020+)
class User {
_privateField = 'private'; // Convention
#truePrivate = 'truly private'; // Language feature
_privateMethod() { }
#truePrivateMethod() { }
}
Comment Your Code Appropriately
Write meaningful comments that explain why, not what. Use JSDoc for documenting functions and classes.
/**
* Calculates the total price including tax
* @param {number} price - The base price
* @param {number} taxRate - The tax rate as a decimal (e.g., 0.1 for 10%)
* @returns {number} The total price including tax
*/
function calculateTotalPrice(price, taxRate) {
// Handle edge cases
if (price < 0 || taxRate < 0) {
throw new Error('Price and tax rate must be non-negative');
}
return price * (1 + taxRate);
}
Testing
Write tests for your code to ensure it works as expected and to catch regressions.
// Example using Jest
describe('calculateTotalPrice', () => {
test('calculates price with tax correctly', () => {
expect(calculateTotalPrice(100, 0.1)).toBe(110);
});
test('handles zero price', () => {
expect(calculateTotalPrice(0, 0.1)).toBe(0);
});
test('throws error for negative price', () => {
expect(() => calculateTotalPrice(-10, 0.1)).toThrow();
});
});
Security Best Practices
Validate User Input
Always validate and sanitize user input to prevent security vulnerabilities like XSS and injection attacks.
// Validate input before using it
function displayUserComment(comment) {
if (typeof comment !== 'string') {
throw new Error('Comment must be a string');
}
// Sanitize the input to prevent XSS
const sanitizedComment = DOMPurify.sanitize(comment);
// Now it's safe to insert into the DOM
commentElement.innerHTML = sanitizedComment;
}
Avoid eval() and new Function()
These functions can execute arbitrary code and pose serious security risks.
Bad Practice:
// Never do this
function calculateFromUserInput(input) {
return eval(input); // Dangerous!
}
Next Steps
Now that you understand JavaScript best practices, consider exploring these related topics:
- Code linting with ESLint
- Code formatting with Prettier
- Design patterns in JavaScript
- Functional programming concepts
- Advanced testing techniques
- Performance optimization