Maison >interface Web >js tutoriel >Clean Code : immuabilité JavaScript, concepts et outils de base

Clean Code : immuabilité JavaScript, concepts et outils de base

Susan Sarandon
Susan Sarandonoriginal
2025-01-17 20:33:15528parcourir

Clean Code: JavaScript immutability, core concepts and tools

Qu'est-ce que la mutation ?

La mutation fait référence à la modification directe d'une valeur existante. En JavaScript, les objets et les tableaux peuvent être modifiés (mutés) par défaut :

<code class="language-javascript">// 变异示例
const user = { name: 'Alice' };
user.name = 'Bob';           // 变异对象属性

const numbers = [1, 2, 3];
numbers.push(4);             // 变异数组
numbers[0] = 0;              // 变异数组元素</code>

Ces mutations peuvent créer des bugs difficiles à trouver, notamment dans les grandes applications.

Pourquoi faut-il éviter les mutations ?

Regardons un exemple simple :

<code class="language-javascript">// 使用变异的代码
const cart = {
  items: [],
  total: 0
};

function addProduct(cart, product) {
  cart.items.push(product);
  cart.total += product.price;
}

// 使用示例
const myCart = cart;
addProduct(myCart, { id: 1, name: "Laptop", price: 999 });
// 直接更改 myCart
console.log(cart === myCart); // true,两个变量指向同一个对象</code>

Problème de mutation :

  1. Références partagées : différentes parties du code peuvent modifier le même objet à l'insu des autres parties.
  2. Effets secondaires : les modifications affecteront d'autres fonctions qui utilisent le même objet.
  3. Difficile à déboguer : impossible de retracer quelle partie du code a modifié l'objet.
  4. Tests complexes : les mutations rendent les tests unitaires plus difficiles à écrire.

Solution : Programmation d'immuabilité

La méthode d'immuabilité crée une nouvelle copie de l'objet à chaque changement :

<code class="language-javascript">// 不变性代码
function addProduct(cart, product) {
  // 创建一个新对象,而不更改原始对象
  return {
    items: [...cart.items, product],
    total: cart.total + product.price
  };
}

// 使用示例
const initialCart = { items: [], total: 0 };
const newCart = addProduct(initialCart, { id: 1, name: "Laptop", price: 999 });

console.log(initialCart); // { items: [], total: 0 }
console.log(newCart);     // { items: [{...}], total: 999 }
console.log(initialCart === newCart); // false,它们是不同的对象</code>

Avantages de cette approche :

  1. Prévisibilité : chaque fonction renvoie un nouvel état, sans effets secondaires cachés.
  2. Suivi des modifications : chaque modification crée un nouvel objet qui peut être suivi.
  3. Facile à tester : les fonctions sont des fonctions pures et plus faciles à tester.
  4. Meilleur débogage : permet de comparer l'état avant et après les modifications.

Outils d'immuabilité modernes

Immer : style d'écriture simple

Immer vous permet d'écrire du code qui ressemble à du code JavaScript normal, mais produit des résultats inchangés :

<code class="language-javascript">import produce from 'immer';

const initialCart = {
  items: [],
  total: 0,
  customer: {
    name: 'Alice',
    preferences: {
      notifications: true
    }
  }
};

// 不使用 Immer(冗长的方法)
const updatedCart = {
  ...initialCart,
  items: [...initialCart.items, { id: 1, name: "Laptop", price: 999 }],
  total: initialCart.total + 999,
  customer: {
    ...initialCart.customer,
    preferences: {
      ...initialCart.customer.preferences,
      notifications: false
    }
  }
};

// 使用 Immer(简单的方法)
const updatedCartImmer = produce(initialCart, draft => {
  draft.items.push({ id: 1, name: "Laptop", price: 999 });
  draft.total += 999;
  draft.customer.preferences.notifications = false;
});</code>

Avantages d'Immer :

  • Syntaxe familière : écrivez du code comme vous le feriez normalement.
  • Aucune nouvelle API à apprendre : utilisez des objets et des tableaux JavaScript classiques.
  • Rapide : copiez uniquement les pièces modifiées.
  • Détection automatique des modifications : suivez les modifications et créez de nouvelles références uniquement en cas de besoin.
  • Fonctionne bien avec TypeScript : toutes les informations de type sont conservées.

Immutable.js : structure de données efficace

Immutable.js fournit des structures de données conçues pour l'immuabilité :

<code class="language-javascript">import { Map, List } from 'immutable';

// 创建不变的数据结构
const cartState = Map({
  items: List([]),
  total: 0
});

// 添加一个项目
const newCart = cartState
  .updateIn(
    ['items'],
    items => items.push(Map({
      id: 1,
      name: "Laptop",
      price: 999
    }))
  )
  .update('total', total => total + 999);

// Immutable.js 方法始终返回新实例
console.log(cartState.getIn(['items']).size); // 0
console.log(newCart.getIn(['items']).size);   // 1

// 轻松比较
console.log(cartState.equals(newCart)); // false

// 转换回常规 JavaScript
const cartJS = newCart.toJS();</code>

Avantages d'Immutable.js :

  • L'utilisation de structures de données immuables est rapide.
  • API riche pour travailler avec des données.
  • Partage de données efficace en mémoire.
  • Utilisez equals() pour vérifier facilement l’égalité.
  • Empêchez les modifications accidentelles.

Configuration immuable d'ESLint

ESLint peut aider à appliquer des pratiques de codage immuables grâce à des règles spécifiques :

<code class="language-javascript">// .eslintrc.js
module.exports = {
  plugins: ['functional'],
  rules: {
    'functional/immutable-data': 'error',
    'functional/no-let': 'error',
    'functional/prefer-readonly-type': 'error'
  }
};</code>

Ces règles :

  • Empêcher la mutation directe des données.
  • Encouragez l'utilisation de const au lieu de let.
  • Il est recommandé d'utiliser des types en lecture seule dans TypeScript.

TypeScript et immuabilité

TypeScript aide à renforcer l'immuabilité grâce à son système de types :

<code class="language-typescript">// 购物车的不变类型
type Product = {
  readonly id: number;
  readonly name: string;
  readonly price: number;
};

type Cart = {
  readonly items: ReadonlyArray<Product>;
  readonly total: number;
};

// TypeScript 防止变异
const cart: Cart = {
  items: [],
  total: 0
};

// 编译错误:items 是只读的
cart.items.push({ id: 1, name: "Laptop", price: 999 });

// 函数必须创建一个新的购物车
function addProduct(cart: Cart, product: Product): Cart {
  return {
    items: [...cart.items, product],
    total: cart.total + product.price
  };
}

// TypeScript 确保原始对象不会更改
const newCart = addProduct(cart, { id: 1, name: "Laptop", price: 999 });</code>

Modificateur en lecture seule pour TypeScript :

  • lecture seule : empêcher les modifications d'attributs.
  • ReadonlyArray : empêche les modifications du tableau.
  • Lecture seule : Rend toutes les propriétés en lecture seule.

Ces types sont vérifiés au moment de la compilation, ce qui permet de détecter les erreurs plus tôt.

Conclusion

L'immuabilité rend votre code plus prévisible et maintenable. Même s'il faut un certain temps pour s'y habituer, les avantages en termes de fiabilité et de maintenabilité en valent la peine.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn