Skip to content

Instantly share code, notes, and snippets.

@abdelghanyMh
Created November 1, 2024 22:08
Show Gist options
  • Save abdelghanyMh/244162b681850d8d8b047983daff9cd4 to your computer and use it in GitHub Desktop.
Save abdelghanyMh/244162b681850d8d8b047983daff9cd4 to your computer and use it in GitHub Desktop.
jetbrains JavaScript Best Practices 2024

Modern JavaScript Best Practices Guide 2024

A comprehensive guide to modern JavaScript best practices for cleaner, more maintainable, and performant code.

Table of Contents

Variable Declaration

Use let and const instead of var for block-scoping and predictable behavior.

// ❌ Avoid
var x = 1;

// ✅ Prefer
const PI = 3.14;
let count = 0;

// Block scoping example
for (let i = 0; i < 5; i++) {
    console.log(i);
}
// console.log(i); // ReferenceError: i is not defined

Classes and OOP

Modern Class Syntax

// ❌ Avoid
function Person(name) {
    this.name = name;
}
Person.prototype.getName = function() {
    return this.name;
}

// ✅ Prefer
class Person {
    constructor(name) {
        this.name = name;
    }
    getName() {
        return this.name;
    }
}

Private Fields

// ❌ Avoid
class User {
    constructor(name) {
        this._name = name; // Convention only, not truly private
    }
}

// ✅ Prefer
class User {
    #name; // True private field
    constructor(name) {
        this.#name = name;
    }
    getName() {
        return this.#name;
    }
}

Modern Function Syntax

Arrow Functions

// ❌ Avoid
const numbers = [1, 2, 3];
numbers.map(function(num) {
    return num * 2;
});

// ✅ Prefer
const numbers = [1, 2, 3];
numbers.map(num => num * 2);

// With this binding
class Calculator {
    constructor() {
        this.value = 0;
    }
    // Arrow function preserves 'this'
    add = (x) => {
        this.value += x;
    }
}

Null Handling

Nullish Coalescing

// ❌ Avoid
const value = someValue || 'default';

// ✅ Prefer
const value = someValue ?? 'default';

// Example
const count = 0;
console.log(count || 10);  // 10 (undesired)
console.log(count ?? 10);  // 0 (correct)

Optional Chaining

// ❌ Avoid
const street = user && user.address && user.address.street;

// ✅ Prefer
const street = user?.address?.street;

Async Programming

Modern Async/Await

// ❌ Avoid
function fetchData() {
    return fetch('api/data')
        .then(response => response.json())
        .then(data => processData(data))
        .catch(error => console.error(error));
}

// ✅ Prefer
async function fetchData() {
    try {
        const response = await fetch('api/data');
        const data = await response.json();
        return processData(data);
    } catch (error) {
        console.error(error);
    }
}

Object Operations

Modern Object Methods

const user = {
    name: 'John',
    age: 30,
    city: 'New York'
};

// Object entries
Object.entries(user).forEach(([key, value]) => {
    console.log(`${key}: ${value}`);
});

// Object values
const values = Object.values(user);
console.log(values); // ['John', 30, 'New York']

// Object keys
const keys = Object.keys(user);
console.log(keys); // ['name', 'age', 'city']

Data Structures

Using Map

// ❌ Avoid
const userRoles = {};
const user = { id: 1 };
userRoles[user] = 'admin'; // user gets converted to string

// ✅ Prefer
const userRoles = new Map();
userRoles.set(user, 'admin');
console.log(userRoles.get(user)); // 'admin'

Using Symbol

const PRIVATE_KEY = Symbol('privateKey');
class MyClass {
    constructor() {
        this[PRIVATE_KEY] = 'secret';
    }
}

const instance = new MyClass();
console.log(Object.keys(instance)); // []
console.log(instance[PRIVATE_KEY]); // 'secret'

Internationalization

Using Intl API

// Format currency
const amount = 123456.789;
const formatter = new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'USD'
});
console.log(formatter.format(amount)); // $123,456.79

// Format dates
const date = new Date();
const dateFormatter = new Intl.DateTimeFormat('en-GB', {
    year: 'numeric',
    month: 'long',
    day: 'numeric'
});
console.log(dateFormatter.format(date)); // 15 October 2024

Common Best Practices

Strict Equality

// ❌ Avoid
console.log(0 == ''); // true (unexpected)
console.log([] == ![]); // true (very unexpected)

// ✅ Prefer
console.log(0 === ''); // false
console.log([] === ![]); // false

Explicit Conditions

// ❌ Avoid
if (value) {
    // ...
}

// ✅ Prefer
if (value !== null && value !== undefined) {
    // ...
}

Handling Large Numbers

// ❌ Avoid direct JSON parse with large numbers
const data = JSON.parse('{"id": 9007199254740999}');

// ✅ Prefer custom parsing for large numbers
const safeData = JSON.parse('{"id": 9007199254740999}', 
    (key, value) => {
        if (key === 'id') return BigInt(value);
        return value;
    }
);

Testing

Using Node.js Built-in Test Runner

import { test } from 'node:test';
import { equal } from 'node:assert';

const sum = (a, b) => a + b;

test('sum function', () => {
    equal(sum(1, 1), 2);
    equal(sum(-1, 1), 0);
    equal(sum(0, 0), 0);
});

Key Takeaways

  1. Use modern syntax (let/const, classes, arrow functions)
  2. Leverage new JavaScript features for null handling
  3. Use async/await for asynchronous operations
  4. Prefer strict equality (===)
  5. Use built-in APIs before adding external dependencies
  6. Write tests using built-in test runners when possible
  7. Use proper documentation (JSDoc) for better code understanding
  8. Be cautious with floating-point calculations
  9. Use appropriate data structures (Map, Set, Symbol)
  10. Leverage the Intl API for formatting

Remember: Project-specific rules always take precedence over general best practices. Stay up-to-date with ECMAScript proposals and releases for the latest JavaScript features and conventions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment