티스토리 뷰

 

 

 

1. 자바스크립트에서 얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy)에 대해 설명해 주세요.


얕은 복사와 깊은 복사를 이해하기 위해서는 원시값과 참조값에 대해 알아야 한다.

자바스크립트에서 값은 원시값과 참조값으로 나뉜다.

 

원시값

  • Number
  • String
  • Boolean
  • Null
  • Undefined

참초값

  • Object
  • Symbol

둘의 차이점은 원래의 값과 복사된 값이 서로에게 영향을 미치느냐, 그렇지 않느냐에 따라 나뉜다.

 

원시값은 값을 복사할 때 복사된 값을 다른 메모리에 할당하기 때문에 (=새로운 메모리 공간에 독립적인 값을 저장)원래의 값과 복사된 값이 서로에게 영향을 미치지 않는다. (아래에서 정리하겠지만 이는 깊은 복사가 된다.)

const a = 1;
let b = a;

b = 2

console.log(a); //1
console.log(b); //2

 

 

반면 참조값은 변수가 객체의 주소를 가리키는 값이기 때문에 복사된 값(주소)이 같은 값을 가리킨다. (아래에서 정리하겠지만 이는 얕은 복사가 된다.)

const a = {number: 1};
let b = a;

b.number = 2

console.log(a); // {number: 2}
console.log(b); // {number: 2}

 

이러한 객체의 특징 때문에 객체를 복사하는 방법은 크게 두가지로 나뉜다. 하나씩 알아보자.

 

 

 

얕은 복사 (Shallow Copy)


얕은 복사란 객체를 복사할 때 기존 값과 복사된 값이 같은 참조를 가리키고 있는 것을 말한다.

객체 안에 객체가 있을 경우 한 개의 객체라도 기존 변수의 객체를 참조하고 있다면 이를 얕은 복사라고 한다.

  • 객체를 복사할 때, 해당 객체만 복사하여 새 객체를 생성한다.
  • 복사된 객체의 인스턴스 변수는 원본 객체의 인스턴스 변수와 같은 메모리 주소를 참조한다.
  • 따라서, 해당 메모리 주소의 값이 변경되면 원본 객체 및 복사 객체의 인스턴스 변수 값은 같이 변경된다.

얕은 복사를 하는 방법은 여러가지가 있다.

 

1. Array.prototype.slice()

2. Object.assign()

3. Spread 연산자 (전개 연산자)

 

const o = { x: { y: 1 } };

// 얕은 복사
const c1 = { ...o }; // 35장 "스프레드 문법" 참고
console.log(c1 === o); // false
console.log(c1.x === o.x); // true

 

 

 

깊은 복사 (Deep Copy)


깊은 복사된 객체는 객체 안에 객체가 있을 경우에도 원본과의 참조가 완전히 끊어진 객체를 말한다.

복사를 하는 목적은 기존 객체의 값만 복사본으로 가져와 별도로 활용하기 위함이 대부분이다. 기존 객체까지 건드린다면 이것은 복사를 하는 목적에 벗어난다.

  • 객체를 복사 할 때, 해당 객체와 인스턴스 변수까지 복사한다.
  • 전부를 복사하여 새 주소에 담기 때문에 참조를 공유하지 않는다.
  • 객체가 참조 타입의 멤버를 포함할 경우 참조값의 복사가 아닌 참조된 객체 자체가 복사되는 것을 의미한다. 원본의 참조는 더 이상 하지 않는다.

깊은 복사를 하는 방법은 여러가지가 있다.

 

1. JSON.parse && JSON.stringify

JSON.stringify()는 객체를 json 문자열로 변환하는데 이 과정에서 원본 객체와의 참조가 모두 끊어진다. 객체를 json 문자열로 변환 후, JSON.parse()를 이용해 다시 원래 객체(자바스크립트 객체)로 만들어준다.

 

- 가장 간단하고 쉬운 방법이다.

- 다른 방법에 비해 느리며 객체가 function일 경우, undefined로 처리한다는 것이 단점이다.

 

2. 커스텀 재귀 함수를 구현한 복사

- 객체의 함수도 제대로 표현할 수 있다.

- 복잡하다는 것이 단점이다.

 

3. Lodash 라이브러리의 cloneDeep 메소드 사용

- 라이브러리를 사용하면 더 쉽고 안전하게 깊은 복사를 할 수 있다.

- 코딩 테스트에는 사용할 수 없다는 것이 단점이다.

 

const o = { x: { y: 1 } };

// 깊은 복사
const c2 = JSON.parse(JSON.stringify(c1))
console.log(c2 === o); // false
console.log(c2.x === o.x); // false

 

 

정리하자면 얕은 복사객체의 참조값(주소값)을 복사하고, 깊은 복사객체의 실제 값을 복사하는 것이다.

 

 


2. var, let, const 를 중복 선언 허용, 스코프, 호이스팅 관점에서 서로 비교해 주세요.


1. 중복 선언 허용

  • let, const 키워드는 중복 선언이 불가능하다
  • var 키워드는 중복 선언이 가능하다
  var myVariable = 'first';
  console.log(myVariable);
  var myVariable = 'second';
  console.log(myVariable);

 

2. 스코프

  • let, const 키워드로 선언한 변수는 if, for, function 등등 어떤 키워드와 관계없이 코드 블록, 즉 {} 중괄호로 감싸진 부분을 기준으로 scope를 갖게 된다 (=블록 레벨 스코프이다)
  • var 키워드로 선언한 변수는 함수(function) 단위로만 scope가 구분되어 있다 (=함수 레벨 스코프이다)
  {
    let x = 3;
  }

  function myFunction() {
    let y = 4;
  }

  console.log(x);
  console.log(y);
  Uncaught ReferenceError: x is not defined

 

 

3. 호이스팅

호이스팅이란?


쉽게말해 변수가 끌어올려지는 현상을 말한다.
호이스팅은 let, const 와 var 키워드에 따라 달라진다.  각각 어떻게 달라지는지 살펴보자.

  • let, const 키워드로 선언한 변수는 선언되기 이전에 사용될 수 없다
console.log(myVariable);
let myVariable; // Uncaught ReferenceError: Cannot access 'myVariable' before initialization
  • var 키워드로 선언한 변수는 선언되기 이전에 사용될 수 있다
console.log(myVariable);
var myVariable; //undefined