Best Practices
## Learning Objectives
- Write clean, maintainable JavaScript code
- Follow established conventions and style guides
- Master debugging techniques
## Code Style
### Naming Conventions
```javascript
// Variables and functions: camelCase
const userName = "Alice";
function calculateTotal() {}
// Constants: UPPER_SNAKE_CASE
const MAX_RETRIES = 3;
const API_URL = "https://api.example.com";
// Classes: PascalCase
class UserAccount {}
class DataProcessor {}
// Private methods: prefix with underscore (or use #)
class Service {
_privateMethod() {}
#trulyPrivateMethod() {}
}
```
### Comments
```javascript
// Good: explain WHY, not WHAT
// Retry failed requests up to 3 times
const MAX_RETRIES = 3;
// Bad: restates the code
// Increment counter by 1
counter++;
```
### Formatting
```javascript
// Use prettier or ESLint for consistent formatting
// Generally: 2 spaces, semicolons, single quotes
const name = "Alice";
const obj = { a: 1, b: 2 };
// Functions: early returns for guard clauses
function process(data) {
if (!data) return null;
// main logic
}
```
## Variables
```javascript
// Prefer const, then let, avoid var
const CONSTANT = "value";
let variable = "can change";
// Single var declaration per scope
let a = 1;
let b = 2;
// Meaningful names
const userAge = 25; // Good
const x = 25; // Bad
```
## Functions
```javascript
// Pure functions when possible
function add(a, b) {
return a + b; // Same inputs → same output, no side effects
}
// Small, focused functions
function validateEmail(email) { /* ... */ }
function sendEmail(email) { /* ... */ }
// Handle defaults gracefully
function greet(name = "Guest") {
return `Hello, ${name}`;
}
// Avoid callback hell - use async/await or promise chains
async function fetchUserData(userId) {
const user = await fetchUser(userId);
const posts = await fetchPosts(user.id);
return { user, posts };
}
```
## Objects and Arrays
```javascript
// Use object destructuring
const { name, age, email } = user;
// Spread operator for immutability
const updatedUser = { ...user, email: "new@example.com" };
// Array methods over loops
const doubled = nums.map(n => n * 2);
const evens = nums.filter(n => n % 2 === 0);
const sum = nums.reduce((a, b) => a + b, 0);
```
## Strings
```javascript
// Template literals for interpolation
const greeting = `Hello, ${name}!`;
const multiLine = `
First line
Second line
`;
// Build strings with array join
const parts = ["a", "b", "c"];
const result = parts.join(", ");
```
## Equality
```javascript
// Always use === instead of ==
if (value === null) { /* ... */ }
if (value !== undefined) { /* ... */ }
// Special case for null/undefined
if (value == null) { /* === null || === undefined */ }
```
## Error Handling
```javascript
// Always handle errors
try {
const data = JSON.parse(input);
} catch (error) {
console.error("Parse error:", error);
throw error;
}
// Create custom errors for specific cases
class AppError extends Error {
constructor(message, code) {
super(message);
this.code = code;
}
}
```
## Async Code
```javascript
// async/await over promise chains
async function loadData() {
try {
const data = await fetchData();
return data;
} catch (error) {
console.error("Load failed:", error);
throw error;
}
}
// Run promises in parallel when possible
const [users, posts] = await Promise.all([
fetchUsers(),
fetchPosts()
]);
```
## Security
```javascript
// Validate and sanitize input
const sanitized = DOMPurify.sanitize(userInput);
// Avoid eval()
const result = Function("x", "return x + 1")(5);
// Use strict mode
"use strict";
// Parameterize database queries (prevent SQL injection)
// Use prepared statements
```
## Performance
```javascript
// Cache DOM queries
const container = document.querySelector(".container");
// Use container instead of querying multiple times
// Batch DOM updates
const fragment = document.createDocumentFragment();
items.forEach(item => fragment.appendChild(createItem(item)));
container.appendChild(fragment);
// Debounce/throttle frequent events
function debounce(fn, delay) {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => fn(...args), delay);
};
}
```
## Testing
```javascript
// Write testable code
function calculateTotal(items) {
return items.reduce((sum, item) => sum + item.price, 0);
}
// Test with Jest
test("calculates total correctly", () => {
const items = [{ price: 10 }, { price: 20 }];
expect(calculateTotal(items)).toBe(30);
});
```
## Linting and Formatting
```javascript
// .eslintrc.json
{
"extends": ["eslint:recommended"],
"env": { "browser": true, "es2021": true },
"rules": {
"no-unused-vars": "error",
"no-console": "warn"
}
}
```
## Summary
- Use meaningful variable and function names
- Prefer `const` over `let`, avoid `var`
- Use strict equality (`===`)
- Handle errors gracefully - never silently fail
- Write pure functions when possible
- Use modern syntax (async/await, arrow functions, destructuring)
- Follow established style guides (ESLint, Prettier)
- Write tests for critical functionality
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →