Avancé25 min de lecture

Patterns JS modernes

Combine les fonctionnalités JavaScript modernes en patterns pratiques — affectation court-circuit, astuces d'objets, mises à jour immutables, et plus encore.

Patterns court-circuit

Les opérateurs logiques de JavaScript peuvent être utilisés pour des patterns conditionnels concis au-delà de la simple logique booléenne.

Valeurs par défaut avec || :

javascript
const name = userInput || 'Anonymous';
// Retourne userInput s'il est truthy, sinon 'Anonymous'

Défaut nullish avec ?? :

javascript
const count = data.count ?? 0;
// Ne revient à 0 que si count est null/undefined
// Préserve 0, '', false (contrairement à ||)

Garde avec && :

javascript
isLoggedIn && showDashboard();
// N'appelle showDashboard() que si isLoggedIn est truthy

const name = user && user.name;
// Retourne user.name si user est truthy, sinon user (null/undefined)

Opérateurs d'affectation logique (ES2021) :

javascript
let config = {};

config.theme ??= 'light';     // affecte si null/undefined
config.debug ||= false;       // affecte si falsy
config.retries &&= config.retries - 1; // affecte si truthy

Conversion en booléen :

javascript
const hasItems = !!items.length;  // 0 → false, 5 → true
const isValid = !!input.trim();   // '' → false, 'hello' → true

Patterns d'objets

JavaScript moderne fournit des raccourcis élégants pour travailler avec des objets.

Propriétés raccourcies — quand le nom de variable correspond à la clé :

javascript
const name = 'Alice';
const age = 30;

// Au lieu de { name: name, age: age }
const user = { name, age };

Noms de propriétés calculés :

javascript
const field = 'email';
const obj = { [field]: 'alice@example.com' };
console.log(obj.email); // 'alice@example.com'

// Clés dynamiques
const prefix = 'user';
const data = {
  [`${prefix}Name`]: 'Alice',
  [`${prefix}Age`]: 30,
};

Object.assign() vs spread :

javascript
// Les deux fusionnent des objets (spread est préféré)
const merged1 = Object.assign({}, defaults, overrides);
const merged2 = { ...defaults, ...overrides };

Object.freeze() — empêche les modifications :

javascript
const config = Object.freeze({ port: 3000, host: 'localhost' });
config.port = 8080; // échoue silencieusement (lance une erreur en mode strict)

Object.keys/values/entries :

javascript
const user = { name: 'Alice', age: 30 };
Object.keys(user);    // ['name', 'age']
Object.values(user);  // ['Alice', 30]
Object.entries(user); // [['name', 'Alice'], ['age', 30]]

Patterns de mise à jour immutables

En JavaScript moderne — surtout avec React et Redux — tu ne dois jamais muter le state directement. À la place, crée de nouvelles copies avec les changements appliqués.

Mise à jour d'objets :

javascript
const user = { name: 'Alice', age: 25, city: 'Paris' };

// Crée un nouvel objet avec l'age mis à jour
const updated = { ...user, age: 26 };
console.log(user.age);    // 25 (original inchangé)
console.log(updated.age); // 26

Ajout d'éléments aux tableaux :

javascript
const items = ['apple', 'banana'];

const added = [...items, 'cherry'];
// ['apple', 'banana', 'cherry']

const prepended = ['mango', ...items];
// ['mango', 'apple', 'banana']

Suppression d'éléments des tableaux :

javascript
const numbers = [1, 2, 3, 4, 5];
const without3 = numbers.filter(n => n !== 3);
// [1, 2, 4, 5]

Mise à jour d'éléments dans les tableaux :

javascript
const todos = [
  { id: 1, text: 'Buy milk', done: false },
  { id: 2, text: 'Clean house', done: false },
];

const toggled = todos.map(todo =>
  todo.id === 1 ? { ...todo, done: true } : todo
);

Mise à jour d'objets imbriqués :

javascript
const state = { user: { name: 'Alice', address: { city: 'Paris' } } };

const newState = {
  ...state,
  user: {
    ...state.user,
    address: {
      ...state.user.address,
      city: 'London',
    },
  },
};

Patterns fonctionnels

Les concepts de programmation fonctionnelle sont largement utilisés en JavaScript moderne.

Fonctions pures — sans effets de bord, la même entrée donne toujours la même sortie :

javascript
// Pure
const add = (a, b) => a + b;
const toUpper = str => str.toUpperCase();

// Impure (modifie l'état externe)
let count = 0;
const increment = () => ++count;

Fonctions d'ordre supérieur — fonctions qui acceptent ou retournent des fonctions :

javascript
// Accepte une fonction
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);

// Retourne une fonction
const multiplier = factor => number => number * factor;
const double = multiplier(2);
const triple = multiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15

Composition — combiner des fonctions :

javascript
const pipe = (...fns) => value =>
  fns.reduce((acc, fn) => fn(acc), value);

const processName = pipe(
  str => str.trim(),
  str => str.toLowerCase(),
  str => str.replace(/\s+/g, '-')
);

console.log(processName('  Hello World  ')); // 'hello-world'

IIFE (Immediately Invoked Function Expression) — pour une initialisation unique :

javascript
const config = (() => {
  const env = 'production';
  return { env, debug: env !== 'production' };
})();

Commodités modernes

Les versions récentes de JavaScript ont ajouté plusieurs fonctionnalités de confort.

Séparateurs numériques pour la lisibilité :

javascript
const billion = 1_000_000_000;
const bytes = 0xFF_FF_FF;
const fraction = 0.000_001;

globalThis — objet global universel :

javascript
// Fonctionne dans les navigateurs, Node.js, web workers, etc.
globalThis.myGlobal = 'hello';

structuredClone() — copie profonde appropriée :

javascript
const original = { a: 1, nested: { b: 2 } };
const deep = structuredClone(original);
deep.nested.b = 99;
console.log(original.nested.b); // 2 (non affecté !)

Array.at() — accès depuis la fin :

javascript
const arr = ['a', 'b', 'c', 'd'];
console.log(arr.at(-1)); // 'd' (dernier élément)
console.log(arr.at(-2)); // 'c' (avant-dernier)

Object.hasOwn() — plus sûr que hasOwnProperty :

javascript
const obj = { name: 'Alice' };
console.log(Object.hasOwn(obj, 'name'));     // true
console.log(Object.hasOwn(obj, 'toString')); // false

String replaceAll() :

javascript
const text = 'foo-bar-baz';
console.log(text.replaceAll('-', '_')); // 'foo_bar_baz'

Patterns modernes en action

html
<div id="output"></div>

<script>
  // Immutable update
  const user = { name: 'Alice', age: 25, city: 'Paris' };
  const updated = { ...user, age: 26 };

  // Short-circuit default
  const displayName = user.nickname ?? user.name;

  // Shorthand properties
  const x = 10, y = 20;
  const point = { x, y };

  // Deep clone with structuredClone
  const original = { data: { items: [1, 2, 3] } };
  const cloned = structuredClone(original);
  cloned.data.items.push(4);

  // Array.at() for last element
  const colors = ['red', 'green', 'blue'];
  const lastColor = colors.at(-1);

  const output = document.getElementById('output');
  output.innerHTML = `
    <p>Original age: ${user.age}, Updated age: ${updated.age}</p>
    <p>Display name: ${displayName}</p>
    <p>Point: {x: ${point.x}, y: ${point.y}}</p>
    <p>Original items: [${original.data.items}] (not mutated)</p>
    <p>Cloned items: [${cloned.data.items}]</p>
    <p>Last color: ${lastColor}</p>
  `;
</script>

Que fait `{ ...user, age: 30 }` ?

Prêt à pratiquer ?

Crée ton compte gratuit pour accéder à l'éditeur de code interactif, lancer les défis et suivre ta progression.