JavaScript์˜ ์–•์€ ๋ณต์‚ฌ์™€ ๊นŠ์€ ๋ณต์‚ฌ ์ฐจ์ด๋ฅผ ์‰ฝ๊ฒŒ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

JavaScript์˜ ์–•์€ ๋ณต์‚ฌ์™€ ๊นŠ์€ ๋ณต์‚ฌ ์ฐจ์ด๋ฅผ ์‰ฝ๊ฒŒ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

D
dongAuthor
7 min read

JavaScript๋กœ ๊ฐœ๋ฐœํ•˜๋‹ค ๋ณด๋ฉด ๊ฐ์ฒด๋ฅผ ๋ณต์‚ฌํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ์ž์ฃผ ์ƒ๊น๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋‹จ์ˆœํžˆ = ์—ฐ์‚ฐ์ž๋กœ ๋ณต์‚ฌํ•˜๋ฉด ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์–ด์š”. ์™œ๋ƒํ•˜๋ฉด ๊ฐ์ฒด๋Š” ์ฐธ์กฐ ํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์ด์ฃ .

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์–•์€ ๋ณต์‚ฌ์™€ ๊นŠ์€ ๋ณต์‚ฌ์˜ ์ฐจ์ด์ , ๊ฐ๊ฐ์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€, ๊ทธ๋ฆฌ๊ณ  ์‹ค๋ฌด์—์„œ ๋ฐ”๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์–•์€ ๋ณต์‚ฌ(Shallow Copy)๋ž€?

์–•์€ ๋ณต์‚ฌ๋Š” ๊ฐ์ฒด์˜ ์ตœ์ƒ์œ„ ์†์„ฑ๋งŒ ๋ณต์‚ฌํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๋ณต์‚ฌ๋œ ๊ฐ์ฒด์™€ ์›๋ณธ ๊ฐ์ฒด๊ฐ€ ๊ฐ™์€ ์ฐธ์กฐ๋ฅผ ๊ณต์œ ํ•˜๊ฒŒ ๋˜์–ด, ์ค‘์ฒฉ๋œ ๊ฐ์ฒด๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด ์›๋ณธ์—๋„ ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค.

์–•์€ ๋ณต์‚ฌ์˜ ๋™์ž‘ ์›๋ฆฌ

์–•์€ ๋ณต์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด ์ƒˆ๋กœ์šด ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜์ง€๋งŒ(o1 !== o2), ๋‚ด๋ถ€์˜ ์ค‘์ฒฉ๋œ ๊ฐ์ฒด๋‚˜ ๋ฐฐ์—ด์€ ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.

const original = {
  name: "ํ™๊ธธ๋™",
  age: 30,
  address: {
    city: "์„œ์šธ",
    district: "๊ฐ•๋‚จ๊ตฌ"
  }
};

const shallowCopy = Object.assign({}, original);

// ์ตœ์ƒ์œ„ ์†์„ฑ ๋ณ€๊ฒฝ - ์›๋ณธ์— ์˜ํ–ฅ ์—†์Œ
shallowCopy.name = "๊น€์ฒ ์ˆ˜";
console.log(original.name); // "ํ™๊ธธ๋™"

// ์ค‘์ฒฉ๋œ ๊ฐ์ฒด ๋ณ€๊ฒฝ - ์›๋ณธ์—๋„ ์˜ํ–ฅ!
shallowCopy.address.city = "๋ถ€์‚ฐ";
console.log(original.address.city); // "๋ถ€์‚ฐ"

์–•์€ ๋ณต์‚ฌ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•

JavaScript์—์„œ ์–•์€ ๋ณต์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค:

1. Object.assign() ์‚ฌ์šฉ

const user = {
  name: "๊น€๋ฏผ์ˆ˜",
  role: "๊ฐœ๋ฐœ์ž"
};

const clone = Object.assign({}, user);

2. ์ „๊ฐœ ๊ตฌ๋ฌธ(Spread Syntax) ์‚ฌ์šฉ

const user = {
  name: "๋ฐ•์ง€์˜",
  role: "๋””์ž์ด๋„ˆ"
};

const clone = { ...user };

3. ๋ฐฐ์—ด์˜ ๊ฒฝ์šฐ

const items = [1, 2, { value: 3 }];

// Array.from()
const copy1 = Array.from(items);

// slice()
const copy2 = items.slice();

// concat()
const copy3 = [].concat(items);

// ์ „๊ฐœ ๊ตฌ๋ฌธ
const copy4 = [...items];

์–•์€ ๋ณต์‚ฌ์˜ ํŠน์ง•

์–•์€ ๋ณต์‚ฌ๋œ ๊ฐ์ฒด์˜ ์ตœ์ƒ์œ„ ์†์„ฑ์„ ์žฌํ• ๋‹นํ•˜๋ฉด ์›๋ณธ ๊ฐ์ฒด์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ค‘์ฒฉ๋œ ๊ฐ์ฒด์˜ ์†์„ฑ์„ ๋ณ€๊ฒฝํ•˜๋ฉด ์›๋ณธ๋„ ํ•จ๊ป˜ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.

const ingredientsList = ["๊ตญ์ˆ˜", { list: ["๊ณ„๋ž€", "๋ฐ€๊ฐ€๋ฃจ", "๋ฌผ"] }];

const ingredientsListCopy = Array.from(ingredientsList);

// ์ตœ์ƒ์œ„ ์š”์†Œ ๋ณ€๊ฒฝ
ingredientsListCopy[0] = "์Œ€๊ตญ์ˆ˜";
console.log(ingredientsList[0]); // "๊ตญ์ˆ˜" (์˜ํ–ฅ ์—†์Œ)

// ์ค‘์ฒฉ๋œ ๊ฐ์ฒด ๋ณ€๊ฒฝ
ingredientsListCopy[1].list = ["์Œ€๊ฐ€๋ฃจ", "๋ฌผ"];
console.log(ingredientsList[1].list); // ["์Œ€๊ฐ€๋ฃจ", "๋ฌผ"] (์˜ํ–ฅ ์žˆ์Œ!)

๊นŠ์€ ๋ณต์‚ฌ(Deep Copy)๋ž€?

๊นŠ์€ ๋ณต์‚ฌ๋Š” ๊ฐ์ฒด์˜ ๋ชจ๋“  ์ค‘์ฒฉ๋œ ์†์„ฑ๊นŒ์ง€ ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ๋ณต์‚ฌ๋ณธ์„ ๋งŒ๋“œ๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๋ณต์‚ฌ๋ณธ์„ ์ˆ˜์ •ํ•ด๋„ ์›๋ณธ ๊ฐ์ฒด์— ์ „ํ˜€ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊นŠ์€ ๋ณต์‚ฌ์˜ ์ •์˜

๋‘ ๊ฐ์ฒด๊ฐ€ ๊นŠ์€ ๋ณต์‚ฌ ๊ด€๊ณ„์— ์žˆ์œผ๋ ค๋ฉด ๋‹ค์Œ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

  1. ๋‘ ๊ฐ์ฒด๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ์ฒด์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค (o1 !== o2)
  2. ์†์„ฑ์˜ ์ด๋ฆ„๊ณผ ์ˆœ์„œ๊ฐ€ ๊ฐ™์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค
  3. ์†์„ฑ ๊ฐ’๋“ค์ด ์„œ๋กœ์˜ ๊นŠ์€ ๋ณต์‚ฌ๋ณธ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค
  4. ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์ด ๊ตฌ์กฐ์ ์œผ๋กœ ๋™์ผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

๊นŠ์€ ๋ณต์‚ฌ์˜ ๋™์ž‘ ์›๋ฆฌ

๊นŠ์€ ๋ณต์‚ฌ๋Š” ์ค‘์ฒฉ๋œ ๋ชจ๋“  ๊ฐ์ฒด๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ณต์‚ฌ๋ณธ์˜ ์–ด๋–ค ๋ถ€๋ถ„์„ ๋ณ€๊ฒฝํ•˜๋”๋ผ๋„ ์›๋ณธ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

const original = {
  name: "์ด์ˆ˜์ง„",
  projects: {
    current: ["ํ”„๋กœ์ ํŠธ A", "ํ”„๋กœ์ ํŠธ B"],
    completed: ["ํ”„๋กœ์ ํŠธ X"]
  }
};

const deepCopy = JSON.parse(JSON.stringify(original));

deepCopy.projects.current.push("ํ”„๋กœ์ ํŠธ C");
console.log(original.projects.current); // ["ํ”„๋กœ์ ํŠธ A", "ํ”„๋กœ์ ํŠธ B"] (์˜ํ–ฅ ์—†์Œ)

๊นŠ์€ ๋ณต์‚ฌ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•

1. JSON.parse(JSON.stringify()) ํ™œ์šฉ

๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๊ณ  ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

const ingredientsList = ["๊ตญ์ˆ˜", { list: ["๊ณ„๋ž€", "๋ฐ€๊ฐ€๋ฃจ", "๋ฌผ"] }];
const ingredientsListDeepCopy = JSON.parse(JSON.stringify(ingredientsList));

ingredientsListDeepCopy[1].list = ["์Œ€๊ฐ€๋ฃจ", "๋ฌผ"];
console.log(ingredientsList[1].list); // ["๊ณ„๋ž€", "๋ฐ€๊ฐ€๋ฃจ", "๋ฌผ"] (์˜ํ–ฅ ์—†์Œ)

์žฅ์ :

  • ๊ตฌํ˜„์ด ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์ ์ž…๋‹ˆ๋‹ค
  • ๋ณ„๋„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค

๋‹จ์ :

  • ํ•จ์ˆ˜๋Š” ๋ณต์‚ฌ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค
  • Date ๊ฐ์ฒด๋Š” ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค
  • undefined, Symbol ๊ฐ™์€ ํŠน์ˆ˜ ๊ฐ’์€ ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค
  • ์ˆœํ™˜ ์ฐธ์กฐ๊ฐ€ ์žˆ์œผ๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค
const obj = {
  date: new Date(),
  func: () => console.log("hello"),
  undef: undefined
};

const copy = JSON.parse(JSON.stringify(obj));
console.log(copy);
// { date: "2024-01-15T10:30:00.000Z" }
// func์™€ undef๋Š” ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค

2. structuredClone() ์‚ฌ์šฉ

JavaScript์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค.

const original = {
  name: "์ตœ์œ ์ง„",
  date: new Date(),
  nested: {
    data: [1, 2, 3]
  }
};

const deepCopy = structuredClone(original);

deepCopy.nested.data.push(4);
console.log(original.nested.data); // [1, 2, 3] (์˜ํ–ฅ ์—†์Œ)
console.log(deepCopy.date instanceof Date); // true

์žฅ์ :

  • Date, RegExp, Map, Set ๋“ฑ ๋‹ค์–‘ํ•œ ๋‚ด์žฅ ๊ฐ์ฒด๋ฅผ ์ •ํ™•ํžˆ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค
  • ์ˆœํ™˜ ์ฐธ์กฐ๋„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
  • ์„ฑ๋Šฅ์ด ์šฐ์ˆ˜ํ•ฉ๋‹ˆ๋‹ค

๋‹จ์ :

  • ํ•จ์ˆ˜๋Š” ์—ฌ์ „ํžˆ ๋ณต์‚ฌ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค
  • ์˜ค๋ž˜๋œ ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ์ง€์›ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

3. ์žฌ๊ท€ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•œ ์ปค์Šคํ…€ ๊ตฌํ˜„

์™„์ „ํ•œ ์ œ์–ด๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ง์ ‘ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function deepClone(obj, hash = new WeakMap()) {
  // null์ด๋‚˜ ์›์‹œ ํƒ€์ž…์€ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }
  
  // ์ˆœํ™˜ ์ฐธ์กฐ ์ฒ˜๋ฆฌ
  if (hash.has(obj)) {
    return hash.get(obj);
  }
  
  // Date, RegExp ๋“ฑ ํŠน์ˆ˜ ๊ฐ์ฒด ์ฒ˜๋ฆฌ
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  
  // ์ƒˆ ๊ฐ์ฒด ์ƒ์„ฑ
  const cloneObj = Array.isArray(obj) ? [] : {};
  hash.set(obj, cloneObj);
  
  // ์žฌ๊ท€์ ์œผ๋กœ ๋ณต์‚ฌ
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }
  
  return cloneObj;
}

const original = {
  name: "์ •๋ฏผํ˜ธ",
  skills: ["JavaScript", "React"],
  experience: {
    years: 5,
    companies: ["A์‚ฌ", "B์‚ฌ"]
  }
};

const copy = deepClone(original);
copy.skills.push("TypeScript");
console.log(original.skills); // ["JavaScript", "React"] (์˜ํ–ฅ ์—†์Œ)

์žฅ์ :

  • ํ•„์š”์— ๋”ฐ๋ผ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค
  • ํŠน์ˆ˜ํ•œ ํƒ€์ž…๋„ ์›ํ•˜๋Š” ๋Œ€๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

๋‹จ์ :

  • ๊ตฌํ˜„๊ณผ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค
  • ์—ฃ์ง€ ์ผ€์ด์Šค๋ฅผ ๋ชจ๋‘ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

4. Lodash ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ™œ์šฉ

lodash๋Š” ์‹ค๋ฌด์—์„œ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

import _ from 'lodash';

const original = {
  name: "๊ฐ•์„œ์—ฐ",
  metadata: {
    tags: ["frontend", "react"],
    createdAt: new Date()
  }
};

const deepCopy = _.cloneDeep(original);

์žฅ์ :

  • ๊ฒ€์ฆ๋œ ๊ตฌํ˜„์œผ๋กœ ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค.
  • ๋Œ€๋ถ€๋ถ„์˜ ์—ฃ์ง€ ์ผ€์ด์Šค๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๋‹จ์ :

  • ์ถ”๊ฐ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฒˆ๋“ค ํฌ๊ธฐ๊ฐ€ ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (๋ฌผ๋ก  lodash์˜ ์šฉ๋Ÿ‰์ด ํฌ์ง€๋Š” ์•Š์ง€๋งŒโ€ฆ)

์–ธ์ œ ์–•์€ ๋ณต์‚ฌ๋ฅผ ์‚ฌ์šฉํ• ๊นŒ?

์–•์€ ๋ณต์‚ฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค:

1. ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ๊ฒฝ์šฐ

์ค‘์ฒฉ๋œ ๊ฐ์ฒด๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋ฉด, ์–•์€ ๋ณต์‚ฌ๊ฐ€ ๋” ๋น ๋ฅด๊ณ  ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

const userConfig = {
  theme: "dark",
  language: "ko"
};

// ์ตœ์ƒ์œ„ ์†์„ฑ๋งŒ ๋ณ€๊ฒฝํ•˜๋ฏ€๋กœ ์–•์€ ๋ณต์‚ฌ๋กœ ์ถฉ๋ถ„
const newConfig = { ...userConfig, theme: "light" };

2. ์ตœ์ƒ์œ„ ์†์„ฑ๋งŒ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒฝ์šฐ

์ค‘์ฒฉ๋œ ๊ฐ์ฒด๋ฅผ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค๋ฉด ์–•์€ ๋ณต์‚ฌ๋งŒ์œผ๋กœ๋„ ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

const product = {
  id: 1,
  name: "๋…ธํŠธ๋ถ",
  price: 1500000
};

const updatedProduct = { ...product, price: 1400000 };

3. React์—์„œ Props ์ „๋‹ฌ

React์—์„œ๋Š” ๋ถˆ๋ณ€์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์–•์€ ๋ณต์‚ฌ๋ฅผ ์ž์ฃผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

const handleUpdate = (newData) => {
  setUser({ ...user, ...newData });
};

์–ธ์ œ ๊นŠ์€ ๋ณต์‚ฌ๋ฅผ ์‚ฌ์šฉํ• ๊นŒ?

๊นŠ์€ ๋ณต์‚ฌ๋Š” ๋‹ค์Œ ์ƒํ™ฉ์—์„œ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค:

1. ์™„์ „ํžˆ ๋…๋ฆฝ์ ์ธ ๋ณต์‚ฌ๋ณธ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ

์›๋ณธ๊ณผ ์™„์ „ํžˆ ๋ถ„๋ฆฌ๋œ ๊ฐ์ฒด๊ฐ€ ํ•„์š”ํ•  ๋•Œ ๊นŠ์€ ๋ณต์‚ฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

const template = {
  title: "๊ธฐ๋ณธ ํ…œํ”Œ๋ฆฟ",
  sections: [
    { type: "header", content: "์ œ๋ชฉ" },
    { type: "body", content: "๋ณธ๋ฌธ" }
  ]
};

// ๊ฐ ์‚ฌ์šฉ์ž๋งˆ๋‹ค ๋…๋ฆฝ์ ์ธ ํ…œํ”Œ๋ฆฟ ํ•„์š”
const userTemplate = structuredClone(template);
userTemplate.sections[0].content = "์‚ฌ์šฉ์ž ์ œ๋ชฉ";

2. ์ค‘์ฒฉ๋œ ๊ฐ์ฒด๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ

๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ๋‹ค๋ฃฐ ๋•Œ ๊นŠ์€ ๋ณต์‚ฌ๊ฐ€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.

const projectData = {
  name: "์‹ ๊ทœ ํ”„๋กœ์ ํŠธ",
  team: {
    frontend: ["๊น€๊ฐœ๋ฐœ", "์ด๋””์ž์ธ"],
    backend: ["๋ฐ•์„œ๋ฒ„", "์ตœ๋””๋น„"]
  }
};

const archivedProject = structuredClone(projectData);
archivedProject.team.frontend.push("์‹ ์ž…์‚ฌ์›");
// original์˜ team์€ ์˜ํ–ฅ๋ฐ›์ง€ ์•Š์Œ

3. ์ƒํƒœ ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ

์‹คํ–‰ ์ทจ์†Œ(Undo) ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

const history = [];

function saveState(currentState) {
  history.push(structuredClone(currentState));
}

function undo() {
  return history.pop();
}

์„ฑ๋Šฅ ๊ณ ๋ ค์‚ฌํ•ญ

๊นŠ์€ ๋ณต์‚ฌ์™€ ์–•์€ ๋ณต์‚ฌ๋Š” ์„ฑ๋Šฅ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์–•์€ ๋ณต์‚ฌ์˜ ์„ฑ๋Šฅ

์–•์€ ๋ณต์‚ฌ๋Š” ์ตœ์ƒ์œ„ ์†์„ฑ๋งŒ ๋ณต์‚ฌํ•˜๋ฏ€๋กœ ๋งค์šฐ ๋น ๋ฆ…๋‹ˆ๋‹ค. ๊ฐ์ฒด์˜ ํฌ๊ธฐ๊ฐ€ ํด์ˆ˜๋ก ๊นŠ์€ ๋ณต์‚ฌ ๋Œ€๋น„ ์„ฑ๋Šฅ ์ด์ ์ด ํฝ๋‹ˆ๋‹ค.

// ๋น ๋ฆ„
const shallowCopy = { ...largeObject };

๊นŠ์€ ๋ณต์‚ฌ์˜ ์„ฑ๋Šฅ

๊นŠ์€ ๋ณต์‚ฌ๋Š” ๋ชจ๋“  ์ค‘์ฒฉ ๊ตฌ์กฐ๋ฅผ ์ˆœํšŒํ•˜๋ฏ€๋กœ ๋‹น์—ฐํžˆ ์‹œ๊ฐ„์ด ๋” ์˜ค๋ž˜ ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค.

// ์ƒ๋Œ€์ ์œผ๋กœ ๋А๋ฆผ
const deepCopy = structuredClone(largeObject);

์„ฑ๋Šฅ ์ตœ์ ํ™” ํŒ

๋Œ€์šฉ๋Ÿ‰ ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฃฐ ๋•Œ๋Š” ๋‹ค์Œ์„ ๊ณ ๋ คํ•˜์„ธ์š”:

  1. ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ๋ณต์‚ฌํ•˜๊ธฐ
const { metadata, ...essentialData } = largeObject;
const copy = structuredClone(essentialData);
  1. ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ํ™œ์šฉ
const cache = new WeakMap();

function getCachedCopy(obj) {
  if (!cache.has(obj)) {
    cache.set(obj, structuredClone(obj));
  }
  return cache.get(obj);
}
  1. ์ ์ ˆํ•œ ๋ฐฉ๋ฒ• ์„ ํƒ
  • ๊ฐ„๋‹จํ•œ ๊ฐ์ฒด: JSON.parse(JSON.stringify())
  • ๋ณต์žกํ•œ ๊ฐ์ฒด: structuredClone()
  • ์ปค์Šคํ…€ ๋กœ์ง ํ•„์š”: ์ง์ ‘ ๊ตฌํ˜„ ๋˜๋Š” Lodash

์ž์ฃผ ๋ฌป๋Š” ์งˆ๋ฌธ

Q: ๋ฐฐ์—ด๋„ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋ณต์‚ฌํ•˜๋‚˜์š”?

๋„ค, ๋ฐฐ์—ด๋„ ๊ฐ์ฒด์ด๋ฏ€๋กœ ๋™์ผํ•œ ์›๋ฆฌ๊ฐ€ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ์–•์€ ๋ณต์‚ฌ๋Š” ์ „๊ฐœ ๊ตฌ๋ฌธ์ด๋‚˜ slice()๋ฅผ, ๊นŠ์€ ๋ณต์‚ฌ๋Š” structuredClone()์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Q: React์—์„œ๋Š” ์–ด๋–ค ๋ณต์‚ฌ ๋ฐฉ์‹์„ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๋‚˜์š”?

React์—์„œ๋Š” ๋Œ€๋ถ€๋ถ„ ์–•์€ ๋ณต์‚ฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ƒํƒœ ์—…๋ฐ์ดํŠธ ์‹œ { ...state } ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ƒˆ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ๋ถˆ๋ณ€์„ฑ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

Q: JSON ๋ฐฉ์‹์˜ ๊นŠ์€ ๋ณต์‚ฌ๋กœ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š๋‚˜์š”?

๊ฐ„๋‹จํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์—๋Š” ์ถฉ๋ถ„ํ•˜์ง€๋งŒ, Date, ํ•จ์ˆ˜, undefined ๋“ฑ์„ ๋‹ค๋ค„์•ผ ํ•œ๋‹ค๋ฉด structuredClone()์ด๋‚˜ Lodash๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค !

References

JavaScript์˜ ์–•์€ ๋ณต์‚ฌ์™€ ๊นŠ์€ ๋ณต์‚ฌ ์ฐจ์ด๋ฅผ ์‰ฝ๊ฒŒ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.