>웹 프론트엔드 >JS 튜토리얼 >클린 코드: JavaScript 불변성, 핵심 개념 및 도구

클린 코드: JavaScript 불변성, 핵심 개념 및 도구

Susan Sarandon
Susan Sarandon원래의
2025-01-17 20:33:15527검색

Clean Code: JavaScript immutability, core concepts and tools

돌연변이란 무엇인가요?

Mutation은 기존 값을 직접 수정하는 것을 말합니다. JavaScript에서는 기본적으로 객체와 배열을 변경(변형)할 수 있습니다.

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

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

이러한 돌연변이는 특히 대규모 애플리케이션에서 찾기 어려운 버그를 생성할 수 있습니다.

왜 돌연변이를 피해야 합니까?

간단한 예를 살펴보겠습니다.

<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>

돌연변이 문제:

  1. 공유 참조: 코드의 다른 부분은 다른 부분이 알지 못하는 사이에 동일한 객체를 변경할 수 있습니다.
  2. 부작용: 변경 사항은 동일한 개체를 사용하는 다른 기능에 영향을 미칩니다.
  3. 디버깅 어려움: 코드의 어느 부분이 객체를 변경했는지 추적할 수 없습니다.
  4. 복잡한 테스트: 돌연변이로 인해 단위 테스트 작성이 더 어려워집니다.

해결책: 불변성 프로그래밍

불변성 방법은 각 변경에 대해 객체의 새 복사본을 만듭니다.

<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>

이 접근 방식의 이점:

  1. 예측 가능성: 모든 함수는 숨겨진 부작용 없이 새로운 상태를 반환합니다.
  2. 변경 사항 추적: 모든 변경 사항은 추적할 수 있는 새로운 개체를 생성합니다.
  3. 테스트하기 쉬움: 함수는 순수 함수이므로 테스트하기가 더 쉽습니다.
  4. 더 나은 디버깅: 변경 전과 후의 상태를 비교할 수 있습니다.

최신 불변성 도구

Immer: 간단한 글쓰기 스타일

Immer를 사용하면 일반 JavaScript 코드처럼 보이지만 결과는 변하지 않는 코드를 작성할 수 있습니다.

<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>

Immer의 장점:

  • 익숙한 구문: 평소처럼 코드를 작성합니다.
  • 배워야 할 새로운 API가 없습니다. 일반 JavaScript 객체와 배열을 사용하세요.
  • 빠른: 변경된 부분만 복사합니다.
  • 자동 변경 감지: 필요할 때만 변경 사항을 추적하고 새 참조를 생성합니다.
  • TypeScript와 잘 작동합니다. 모든 유형 정보가 보존됩니다.

Immutable.js: 효율적인 데이터 구조

Immutable.js는 불변성을 위해 설계된 데이터 구조를 제공합니다.

<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>

Immutable.js의 장점:

  • 불변 데이터 구조를 사용하면 빠릅니다.
  • 데이터 작업을 위한 풍부한 API.
  • 메모리 효율적인 데이터 공유.
  • 동일성을 쉽게 확인하려면 equals()를 사용하세요.
  • 우발적인 변경을 방지하세요.

ESLint의 불변 구성

ESLint는 특정 규칙을 통해 불변 코딩 관행을 시행하는 데 도움이 될 수 있습니다.

<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>

이러한 규칙은 다음과 같습니다.

  • 직접적인 데이터 변형을 방지하세요.
  • let 대신 const를 사용하도록 권장합니다.
  • TypeScript에서는 읽기 전용 유형을 사용하는 것이 좋습니다.

TypeScript와 불변성

TypeScript는 유형 시스템을 통해 불변성을 강화하는 데 도움이 됩니다.

<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>

TypeScript에 대한 읽기 전용 수정자:

  • 읽기 전용: 속성 변경을 방지합니다.
  • ReadonlyArray: 배열 변경을 방지합니다.
  • 읽기 전용: 모든 속성을 읽기 전용으로 만듭니다.

이러한 유형은 컴파일 타임에 확인되므로 오류를 조기에 발견하는 데 도움이 됩니다.

결론

불변성은 코드를 더욱 예측 가능하고 유지 관리 가능하게 만듭니다. 익숙해지는 데 시간이 좀 걸리지만 안정성과 유지 관리 용이성의 이점은 그만한 가치가 있습니다.

위 내용은 클린 코드: JavaScript 불변성, 핵심 개념 및 도구의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.