๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
JavaScript

[JavaScript] ๊นŠ์€ ๋ณต์‚ฌ(Shllow copy), ์–•์€ ๋ณต์‚ฌ(Deep copy)

by junvely 2023. 2. 23.

๐Ÿ™Œ ๊นŠ์€๋ณต์‚ฌ, ์–•์€ ๋ณต์‚ฌ

์–•์€ ๋ณต์‚ฌ๋Š” ๊ฐ์ฒด์˜ ์ฐธ์กฐ๊ฐ’(์ฃผ์†Œ ๊ฐ’)์„ ๋ณต์‚ฌํ•˜๊ณ , ๊นŠ์€ ๋ณต์‚ฌ๋Š” ๊ฐ์ฒด์˜ ์‹ค์ œ ๊ฐ’์„ ๋ณต์‚ฌํ•œ๋‹ค.

1. Primitive ํƒ€์ž… : ๊นŠ์€ ๋ณต์‚ฌ : ์›์‹œ๊ฐ’์€ ๊ฐ’์„ ๋ณต์‚ฌ ํ•  ๋•Œ ๋ณต์‚ฌ๋œ ๊ฐ’์„ ๋‹ค๋ฅธ ๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹น ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์›๋ž˜์˜ ๊ฐ’๊ณผ ๋ณต์‚ฌ๋œ ๊ฐ’์ด ์„œ๋กœ์—๊ฒŒ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๋Š”๋‹ค

let a = 2;
let b = a;
console.log(b); //2
b = 5;
console.log(a); //2
console.log(b); //5 => primitiveํƒ€์ž…์€ ์„œ๋กœ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๋Š”๋‹ค.

2. Object ํƒ€์ž… : ์–•์€ ๋ณต์‚ฌ : ์ฐธ์กฐ๊ฐ’์€ ๋ณ€์ˆ˜๊ฐ€ ๊ฐ์ฒด์˜ ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์— ์ฐธ์กฐ๊ฐ’(์ฃผ์†Œ)๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๊ฐ™์€ ๊ฐ’์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ๋”ฐ๋ผ์„œ ํ•œ์ชฝ์˜ ๊ฐ’์„ ๋ณ€๊ฒฝ ํ•  ๊ฒฝ์šฐ, ๊ฐ™์€ ์ฐธ์กฐ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์— ์–‘์ชฝ ๊ฐ’์ด ๋ชจ๋‘ ๋ณ€๊ฒฝ๋œ๋‹ค.

const fruit1 = { name: "apple" };
const fruit2 = fruit1;
fruit2.name = "apple";

console.log(fruit1.name); //apple
console.log(fruit2.name); //apple
console.log(fruit1.name === fruit2.name); //true

- ์–•์€ ๋ณต์‚ฌํ•œ ๋ณ€์ˆ˜๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค๋ฉด, ์›๋ณธ ๊ฐ์ฒด ๊นŒ์ง€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ฃผ์˜ํ•˜์—ฌ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

 

๐Ÿ”—์–•์€ ๋ณต์‚ฌ(Shllow copy)

์–•์€ ๋ณต์‚ฌ๋ž€ ๊ฐ์ฒด๋ฅผ ๋ณต์‚ฌํ•  ๋•Œ ๊ธฐ์กด ๊ฐ’๊ณผ ๋ณต์‚ฌ๋œ ๊ฐ’์ด ๊ฐ™์€ ์ฐธ์กฐ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.
๊ฐ์ฒด ์•ˆ์— ๊ฐ์ฒด๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ ํ•œ ๊ฐœ์˜ ๊ฐ์ฒด๋ผ๋„ ๊ธฐ์กด ๋ณ€์ˆ˜์˜ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ์ด๋ฅผ ์–•์€ ๋ณต์‚ฌ๋ผ๊ณ  ํ•œ๋‹ค.

=> ๊ฐ์ฒด ์ž์ฒด๋Š” ๋‹ค๋ฅธ ์ƒˆ ๊ฐ์ฒด์ง€๋งŒ, ๊ฐ์ฒด ๋‚ด๋ถ€์˜ ๊ฐ’์ด ํด๋ก  ํ•œ ๊ฐ์ฒด ๊ฐ’์˜ ์ฐธ์กฐ๊ฐ’์„ ๋ณต์‚ฌํ•˜๋Š” ๊ฒฝ์šฐ

-  1 ๋ ˆ๋ฒจ(1์ฐจ์› ๋ฐฐ์—ด,๊ฐ์ฒด)์— ๋Œ€ํ•ด์„œ๋Š” ๊นŠ์€ ๋ณต์‚ฌ๊ฐ€ ํ—ˆ์šฉ๋˜๋‚˜ 2 ๋ ˆ๋ฒจ(2์ฐจ์› ๋ฐฐ์—ด)์ด์ƒ ๋ถ€ํ„ฐ๋Š” ๊นŠ์€ ๋ณต์‚ฌ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค.

 

1. ๋ฐฐ์—ด์˜ ๋ณต์‚ฌ : Array.slice(), Array.concat(), Array.from()

๊ธฐ์กด ๋ฐฐ์—ด์—์„œ ์ถ”์ถœํ•˜์—ฌ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ๋ฆฌํ„ดํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋“ค์ด๋‹ค. 1์ฐจ์› ๋ฐฐ์—ด์ด๋‚˜ ๊ฐ์ฒด๊นŒ์ง€๋Š” ๊นŠ์€ ๋ณต์‚ฌ๊ฐ€ ํ—ˆ์šฉ๋˜๋‚˜, 2์ฐจ์› ์ด์ƒ ๋ถ€ํ„ฐ๋Š” ์–•์€ ๋ณต์‚ฌํ•˜์—ฌ ์›๋ณธ ๊ฐ์ฒด์˜ ์ฐธ์กฐ๊ฐ’์„ ๋ณต์‚ฌํ•œ๋‹ค.

 

2. Object.assign()

Object.assign(์ƒ์„ฑํ•  ๊ฐ์ฒด, ๋ณต์‚ฌํ•  ๊ฐ์ฒด)

let user = {
  name: "John",
  age: 30
};

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

๋ฉ”์†Œ๋“œ์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ ๋นˆ ๊ฐ์ฒด๋ฅผ ๋„ฃ์–ด์ฃผ๊ณ  ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ ๋ณต์‚ฌํ•  ๊ฐ์ฒด๋ฅผ ๋„ฃ์–ด์ค€๋‹ค.

๋ณต์‚ฌ๋œ ๊ฐ์ฒด user2 ์ž์ฒด๋Š” ๊ธฐ์กด object์™€ ๋‹ค๋ฅธ ์ƒˆ ๊ฐ์ฒด์ง€๋งŒ ๊ทธ ์•ˆ์— ๋“ค์–ด๊ฐ€ ์žˆ๋Š” ๊ฐ’์€ ๊ธฐ์กด object์•ˆ์˜ ๊ฐ’๊ณผ ๊ฐ™์€ ์ฐธ์กฐ ๊ฐ’์„ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋‹ค. => ๊ฐ์ฒด ์ž์ฒด๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด์ง€๋งŒ, ๊ฐ์ฒด ์•ˆ์˜ ๊ฐ’์€ ๋ณต์‚ฌํ•œ ๊ฐ์ฒด ์•ˆ์˜ ์ฐธ์กฐ๊ฐ’์„ ๋ณต์‚ฌํ•œ๋‹ค.

 

3. Spread ์—ฐ์‚ฐ์ž(...)

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์–•์€ ๋ณต์‚ฌ์ด๋‹ค.

const a = { name: "apple", obj: { one: 1, two: 2 }, arr: [1, 2] };
const b = { ...a };
b.name = "ellie";
b.obj.one = 2;

console.log(a.name === b.name); //false 
console.log(a.obj.one === b.obj.one); //true => object ํƒ€์ž…์€ ๊ฐ™์€ ref์ฐธ์กฐ๊ฐ’์ด๋ฏ€๋กœ ๋ณ€๊ฒฝ ์‹œ ๊ฐ™์ด ๋ณ€๊ฒฝ๋จ

 

 

โ›“๏ธ๊นŠ์€ ๋ณต์‚ฌ(Deep copy)

๊นŠ์€ ๋ณต์‚ฌ๋œ ๊ฐ์ฒด๋Š” ๊ฐ์ฒด ์•ˆ์— ๊ฐ์ฒด๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ์—๋„ ์›๋ณธ๊ณผ์˜ ์ฐธ์กฐ๊ฐ€ ์™„์ „ํžˆ ๋Š์–ด์ง„ ๊ฐ์ฒด๋ฅผ ๋งํ•œ๋‹ค.

 

1.JSON.parse && JSON.stringify

JSON.stringify()๋Š” ๊ฐ์ฒด๋ฅผ json ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜๋Š”๋ฐ ์ด ๊ณผ์ •์—์„œ ์›๋ณธ ๊ฐ์ฒด์™€์˜ ์ฐธ์กฐ๊ฐ€ ๋ชจ๋‘ ๋Š์–ด์ง„๋‹ค. ๊ฐ์ฒด๋ฅผ json ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ ํ›„, JSON.parse()๋ฅผ ์ด์šฉํ•ด ๋‹ค์‹œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด)๋กœ ๋งŒ๋“ค์–ด์ค€๋‹ค.

์ด ๋ฐฉ๋ฒ•์ด ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๊ณ  ์‰ฝ์ง€๋งŒ 1. ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์— ๋น„ํ•ด ๋Š๋ฆฌ๋‹ค๋Š” ๊ฒƒ๊ณผ 2. ๊ฐ์ฒด๊ฐ€ ํ•จ์ˆ˜์ผ ๊ฒฝ์šฐ,  undefined๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค๋Š” ๊ฒƒ, 3. ๋ชจ๋“  ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณต์‚ฌ๋˜์ง€ ์•Š๊ฑฐ๋‚˜ ํƒ€์ž…์ด ๋ณ€๊ฒฝ๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.(new Date()ํ•จ์ˆ˜ ๊ฐ™์€ ๊ฒฝ์šฐ์˜ ๋ฐ์ดํ„ฐ ํƒ€์ž… ๋‹ค๋ฆ„ ๋“ฑ)

const a = { name: "apple", obj: { one: 1, two: 2 }, arr: [1, 2] };
const c = JSON.parse(JSON.stringify(a));
c.name = "eliie";
c.obj.one = 3;
c.arr.push(3);

console.log(c);
console.log(a.name === c.name); //false
console.log(a.obj.one === c.obj.one); //false => object ํƒ€์ž…์€ ๊ฐ™์€ ref์ฐธ์กฐ๊ฐ’์ด๋ฏ€๋กœ ๋ณ€๊ฒฝ ์‹œ ๊ฐ™์ด ๋ณ€๊ฒฝ๋จ
console.log(a.arr === c.arr); //false => object ํƒ€์ž…์€ ๊ฐ™์€ ref์ฐธ์กฐ๊ฐ’์ด๋ฏ€๋กœ ๋ณ€๊ฒฝ ์‹œ ๊ฐ™์ด ๋ณ€๊ฒฝ๋จ

 

2. Lodash ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋” ์‰ฝ๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ๊นŠ์€ ๋ณต์‚ฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์„ค์น˜๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ ๊ณผ ์ผ๋ฐ˜์ ์ธ ๊ฐœ๋ฐœ์—๋Š” ํšจ์œจ์ ์ด๊ฒ ์ง€๋งŒ, ์ฝ”๋”ฉ ํ…Œ์ŠคํŠธ์—๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ด ๋‹จ์ ์ด๋‹ค.

const deepCopy = require("lodash.clonedeep")
const copy = deepCopy(object);

 

3. ๋ฐ˜๋ณต๋ฌธ์œผ๋กœ ์ผ์ผํžˆ ๋ณต์‚ฌ, ์žฌ๊ท€ ํ•จ์ˆ˜

์ผ์ผํžˆ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋ฉฐ ๋ณต์žกํ•˜๋‹ค๋Š” ๊ฒƒ์ด ๋‹จ์ ์ด๋‹ค.

let user = {
  name: "John",
  age: 30
};

let clone = {}; // ์ƒˆ๋กœ์šด ๋นˆ ๊ฐ์ฒด

// ๋นˆ ๊ฐ์ฒด์— user ํ”„๋กœํผํ‹ฐ ์ „๋ถ€๋ฅผ ๋ณต์‚ฌํ•ด ๋„ฃ์Šต๋‹ˆ๋‹ค.
for (let key in user) {
  clone[key] = user[key];
}

// ์ด์ œ clone์€ ์™„์ „ํžˆ ๋…๋ฆฝ์ ์ธ ๋ณต์ œ๋ณธ์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
clone.name = "Pete"; // clone์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.

alert( user.name ); // ๊ธฐ์กด ๊ฐ์ฒด์—๋Š” ์—ฌ์ „ํžˆ John์ด ์žˆ์Šต๋‹ˆ๋‹ค.
let origin = {
    a: 1,
    b: { c: 2 }
};
//๋ฐฉ๋ฒ• 1
function isCopyObj(origin) {
    let res = {};

    for (let key in origin) {
      if (typeof origin[key] === 'object') {
          res[key] = isCopyObj(obj[key]);
      } else {
          res[key] = origin[key];
      }
    }

    return res;
}

let copy = isCopyObj(origin);

copy.b.c = 3
console.log(origin.b.c === copy.b.c) //false


// ๋ฐฉ๋ฒ• 2
const object = {
  a: "a",
  number: {
    one: 1,
    two: 2,
  },
  arr: [1, 2, [3, 4]],
};
 
function deepCopy(object) {
  if (object === null || typeof object !== "object") {
    return object;
  }
  // ๊ฐ์ฒด์ธ์ง€ ๋ฐฐ์—ด์ธ์ง€ ํŒ๋‹จ
  const copy = Array.isArray(object) ? [] : {};
 
  for (let key of Object.keys(object)) {
    copy[key] = deepCopy(object[key]);
  }
 
  return copy;
}
 
const copy = deepCopy(object);
 
copy.number.one = 3;
copy.arr[2].push(5);
 
console.log(object === copy); // false
console.log(object.number.one === copy.number.one); // false
console.log(object.arr === copy.arr); // false
 
console.log(object); // { a: 'a', number: { one: 1, two: 2 }, arr: [ 1, 2, [ 3, 4 ] ] }
console.log(copy); // { a: 'a', number: { one: 3, two: 2 }, arr: [ 1, 2, [ 3, 4, 5 ] ] }

deepCopy() ํ•จ์ˆ˜๋กœ obj ๊ฐ์ฒด๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ณด๋‚ธ ๋‹ค์Œ ์ธ์ˆ˜๊ฐ’์ด ๊ฐ์ฒด๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ์—” ๊ทธ๋ƒฅ obj๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ๊ฐ์ฒด์ธ ๊ฒฝ์šฐ ๊ฐ์ฒด์˜ ๊ฐ’ ๋งŒํผ ๋ฃจํ”„๋ฅผ ๋Œ๊ณ  ์žฌ๊ท€๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ณต์‚ฌ๋œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

๋ณต์‚ฌ๋œ copyObj ๊ฐ์ฒด๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด 2์ฐจ์› ๊ฐ์ฒด์˜ ๊ฐ’๋„ ๊นŠ์€ ๋ณต์‚ฌ(Deep Copy)๊ฐ€ ๋˜์—ˆ์œผ๋ฉฐ, ๊ฐ์ฒด์˜ ํ•จ์ˆ˜๋„ ์ œ๋Œ€๋กœ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

<์ฐธ๊ณ >

 

shallow copy, deep copy(JS)

์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ฌธ์ œ๋ฅผ ํ’€๋ฉด์„œ ์ž์ฃผ ๊ฒช๊ฒŒ ๋˜๋Š” ์–•์€ ๋ณต์‚ฌ์™€ ๊นŠ์€ ๋ณต์‚ฌ์— ๋Œ€ํ•ด ์ •๋ฆฌํ•˜๊ณ ์ž ํ•œ๋‹ค.

jonghyun-park.medium.com

 

 

[JavaScript] ๊นŠ์€ ๋ณต์‚ฌ, ์–•์€ ๋ณต์‚ฌ

๊นŠ์€ ๋ณต์‚ฌ, ์–•์€ ๋ณต์‚ฌ ๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜์ž๋ฉด ์–•์€ ๋ณต์‚ฌ๋Š” ๊ฐ์ฒด์˜ ์ฐธ์กฐ๊ฐ’(์ฃผ์†Œ ๊ฐ’)์„ ๋ณต์‚ฌํ•˜๊ณ , ๊นŠ์€ ๋ณต์‚ฌ๋Š” ๊ฐ์ฒด์˜ ์‹ค์ œ ๊ฐ’์„ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋จผ์ €, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๊ฐ’์€ ์›์‹œ๊ฐ’๊ณผ ์ฐธ์กฐ๊ฐ’ ๋‘ ๊ฐ€์ง€ ๋ฐ

bbangson.tistory.com

 

 

[Javascript] ์–•์€ ๋ณต์‚ฌ, ๊นŠ์€ ๋ณต์‚ฌ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๊ฐ’์€ ์›์‹œ๊ฐ’๊ณผ ์ฐธ์กฐ๊ฐ’์œผ๋กœ ๋‚˜๋‰œ๋‹ค. ์›์‹œ๊ฐ’ Number String Boolean Null Undefined ์ฐธ์กฐ๊ฐ’ Object Symbol ์›์‹œ๊ฐ’์€ ๊ฐ’์„ ๋ณต์‚ฌ ํ•  ๋•Œ ๋ณต์‚ฌ๋œ ๊ฐ’์„ ๋‹ค๋ฅธ ๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹น ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์›๋ž˜์˜ ๊ฐ’๊ณผ

velog.io