- Published on
25 JavaScript Best Practices for Modern Development
- Authors
- Name
- Mohit Verma
Modern JavaScript development requires careful attention to best practices to ensure maintainable, efficient, and secure code. Here are 25 essential best practices that every JavaScript developer should follow.
1. Use Strict Mode
Always enable strict mode to catch common mistakes and prevent unsafe actions:
'use strict';
// This will throw an error in strict mode
mistypedVariable = 17; // ReferenceError
2. Prefer const and let over var
Use const
by default, and let
when you need to reassign variables:
// Good
const API_KEY = 'abc123';
let userCount = 0;
// Bad
var API_KEY = 'abc123';
3. Use Arrow Functions for Callbacks
Arrow functions provide cleaner syntax and lexical this
binding:
// Good
const numbers = [1, 2, 3];
const doubled = numbers.map(num => num * 2);
// Bad
const doubled = numbers.map(function(num) {
return num * 2;
});
4. Implement Proper Error Handling
Always handle errors appropriately:
async function fetchData() {
try {
const response = await fetch('/api/data');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Fetch error:', error);
// Handle error appropriately
throw new Error('Failed to fetch data');
}
}
5. Use Template Literals
Use template literals for string interpolation:
// Good
const name = 'John';
const greeting = `Hello, ${name}!`;
// Bad
const greeting = 'Hello, ' + name + '!';
6. Implement Proper Async/Await Error Handling
Handle async operations properly:
async function processData() {
try {
const data = await fetchData();
return processResult(data);
} catch (error) {
handleError(error);
} finally {
cleanup();
}
}
7. Use Object Destructuring
Destructure objects for cleaner code:
// Good
const { name, age, email } = user;
// Bad
const name = user.name;
const age = user.age;
const email = user.email;
8. Implement Module Pattern
Use ES modules for better code organization:
// userService.js
export const userService = {
async getUser(id) {
// Implementation
},
async updateUser(id, data) {
// Implementation
}
};
// Usage
import { userService } from './userService';
9. Use Array Methods Instead of Loops
Prefer array methods for better readability:
// Good
const evenNumbers = numbers.filter(num => num % 2 === 0);
const doubled = numbers.map(num => num * 2);
const sum = numbers.reduce((acc, num) => acc + num, 0);
// Bad
const evenNumbers = [];
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 === 0) {
evenNumbers.push(numbers[i]);
}
}
10. Implement Proper Type Checking
Use proper type checking methods:
function processValue(value) {
if (typeof value !== 'number') {
throw new TypeError('Value must be a number');
}
if (!Array.isArray(value)) {
throw new TypeError('Value must be an array');
}
if (!(value instanceof Date)) {
throw new TypeError('Value must be a Date object');
}
}
11. Use Default Parameters
Implement default parameters for functions:
// Good
function createUser(name = 'Anonymous', age = 0) {
return { name, age };
}
// Bad
function createUser(name, age) {
name = name || 'Anonymous';
age = age || 0;
return { name, age };
}
12. Implement Proper Memory Management
Clean up resources and remove event listeners:
class Component {
constructor() {
this.handleClick = this.handleClick.bind(this);
document.addEventListener('click', this.handleClick);
}
destroy() {
document.removeEventListener('click', this.handleClick);
}
}
13. Use Optional Chaining
Implement optional chaining for safer property access:
// Good
const userName = user?.profile?.name;
// Bad
const userName = user && user.profile && user.profile.name;
14. Implement Proper Data Validation
Validate data before processing:
function processUserData(data) {
const requiredFields = ['name', 'email', 'age'];
for (const field of requiredFields) {
if (!(field in data)) {
throw new Error(`Missing required field: ${field}`);
}
}
if (typeof data.age !== 'number' || data.age < 0) {
throw new Error('Invalid age');
}
// Process data
}
15. Use Meaningful Variable Names
Choose descriptive and meaningful names:
// Good
const userAuthentication = {
isAuthenticated: false,
lastLoginDate: new Date(),
};
// Bad
const auth = {
a: false,
d: new Date(),
};
16. Implement Performance Optimizations
Use performance optimization techniques:
// Debounce example
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
const debouncedSearch = debounce(searchFunction, 300);
17. Use Proper Promise Handling
Handle promises correctly:
// Good
Promise.all([
fetchUsers(),
fetchPosts(),
fetchComments()
])
.then(([users, posts, comments]) => {
// Process data
})
.catch(error => {
// Handle errors
});
18. Implement Security Best Practices
Follow security best practices:
// Sanitize user input
function displayUserInput(input) {
const sanitized = DOMPurify.sanitize(input);
element.innerHTML = sanitized;
}
// Use HttpOnly cookies
document.cookie = 'session=123; HttpOnly; Secure';
19. Use Proper Comparison Operators
Use strict equality operators:
// Good
if (value === undefined) {
// Handle undefined
}
// Bad
if (value == undefined) {
// This also matches null
}
20. Implement Proper Logging
Use proper logging mechanisms:
const logger = {
info: (message, ...args) => {
console.log(new Date(), 'INFO:', message, ...args);
},
error: (message, ...args) => {
console.error(new Date(), 'ERROR:', message, ...args);
}
};
21. Use Object Shorthand Syntax
Use object shorthand when possible:
// Good
const name = 'John';
const age = 30;
const user = { name, age };
// Bad
const user = { name: name, age: age };
22. Implement Proper Testing
Write testable code:
// Good - Pure function, easy to test
function calculateTotal(items) {
return items.reduce((sum, item) => sum + item.price, 0);
}
// Test
test('calculateTotal returns correct sum', () => {
const items = [
{ price: 10 },
{ price: 20 }
];
expect(calculateTotal(items)).toBe(30);
});
23. Use Modern JavaScript Features
Leverage modern JavaScript features:
// Use nullish coalescing
const value = data ?? defaultValue;
// Use optional chaining with function calls
const result = obj?.method?.();
// Use array/object spread
const newArray = [...oldArray, newItem];
const newObject = { ...oldObject, newProp: value };
24. Implement Proper Error Classes
Create custom error classes:
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = 'ValidationError';
}
}
class APIError extends Error {
constructor(message, statusCode) {
super(message);
this.name = 'APIError';
this.statusCode = statusCode;
}
}
25. Use Proper Documentation
Document your code properly:
/**
* Calculates the total price of items in the cart
* @param {Array<Object>} items - Array of cart items
* @param {number} items[].price - Price of each item
* @param {number} [discount=0] - Optional discount percentage
* @returns {number} Total price after discount
* @throws {ValidationError} If items array is empty
*/
function calculateCartTotal(items, discount = 0) {
if (!items.length) {
throw new ValidationError('Cart is empty');
}
const total = items.reduce((sum, item) => sum + item.price, 0);
return total * (1 - discount / 100);
}
Conclusion
Following these JavaScript best practices will help you:
- Write more maintainable code
- Improve code performance
- Enhance security
- Reduce bugs
- Make code more testable
Remember to:
- Keep your code clean and organized
- Follow consistent naming conventions
- Write comprehensive tests
- Document your code properly
- Stay updated with modern JavaScript features
Keep learning and adapting these practices as JavaScript continues to evolve!