자바스크립트

Section 5. 자바스크립트 객체의 스프레드와 디스트럭쳐링

포칼이 2023. 3. 30. 12:16

I. 스프레드 spread

1. 기본 문법

const class1 = {
  x: 1, y: 'A', z: true
};

const class2 = { ...class1 };

// 아래의 참조복사 코드와 다름!
// const class2 = class1;

console.log(class2);

스프레드 연산자를 사용해서 class1의 객체의 프로퍼티들을 class2 객체에 넣었다. 

하지만 단순히 class2가 class1과 같은 객체를 바라보게 하는 참조복사와는 다르다. 

즉, 스프레드 연산자를 사용해서 const class2 = {...class1}을 하면 class1의 프로퍼티들을 하나하나 복사하여 가져오는 것이라고 생각하면 된다. 

 

2. 특정 객체의 프로퍼티를 포함하는 다른 객체 생성에 유용

const class1 = {
  a: 1, b: 'A', c: true
};
const class2 = {
  d: { x: 10, y: 100 }, e: [1, 2, 3]
};
const class3 = {
  ...class1, z: 0
}
const class4 = {
  ...class2, ...class3, ...class2.d
}

console.log(class3); //{a: 1, b: 'A', c: true, z: 0}

console.log(class4); //{d: {…}, e: Array(3), a: 1, b: 'A', c: true, …}

스프레드 연산자를 통해 간단하게 객체들을 생성 했다.

 

3. 중복되는 프로퍼티는 뒤의 것이 덮어쓴다

const class1 = {
  ...{ a: 1, b: 2 },
  ...{ b: 3, c: 4, d: 5 },
  ...{ c: 6, d: 7, e: 8 }
}

console.log(class1); //{a: 1, b: 3, c: 6, d: 7, e: 8}

 

4. 복사의 깊이

const class1 = {
  x: 1,
  y: { a: 2 },
  z: [3, 4]
};

const class2 = { ...class1 };
class1.x++;
class1.y.a++;
class1.z[0]++;

console.log(class1);
console.log(class2);

스프레드 연산자로 class2를 class1에서 가져와서 생성을 했다. 

그리고 class1의 x, y, z 프로퍼티를 변경했을때 각각 출력이 어떻게 되는지 확인을 해보면 다음과 같다. 

원시 값인 x는 값 그 자체가 복사가 되었기 때문에 class1의 x값이 바뀌었어도 class2의 x값과는 상관이 없는 것을 볼 수 있다. 

참조 자료형인 객체나 배열은 역시, 여기서도 주소만 복사가 된 것이기 때문에 주소가 가리키는 값이 변경되면 그 주소를 가리키고 있는 class1이나 class2의 값은 같이 영향을 받게 되는 것이다. 

 

정리하자면 다음과 같다.

  • 해당 객체 바로 안쪽의 원시값은 복제하지만 참조값은 같은 값을 가리킨다
  • 원시값만 있는 객체만 값에 의한 복사 즉, 얕은 복사 라고 한다

II. 디스트럭쳐링 destructuring

1. 문법

기존 코드는 다음과 같다.

const obj1 = {
  x: 1, y: 2, z: 3
};

const x = obj1.x;
const y = obj1.y;
const z = obj1.z;

console.log(x, y, z); //1 2 3

x, y, z에 obj1의 프로퍼티값을 각각 할당해 주려고 하는 코드이다.

 

디스트럭쳐링으로 간략화

const obj1 = {
  x: 1, y: 2, z: 3
};

const {x, y, z} = obj1;

console.log(x, y, z); //1 2 3

드스트럭쳐링으로 기존의 코드가 간결해졌다. 이렇게 x, y, z같이 식별자가 같으면 이런 문법으로 사용한다는 것을 알고 넘아가자.

 

일부만 가져오는 것도 가능

const obj1 = {
  x: 1, y: 2, z: 3
};

const {x, z} = obj1;

console.log(x, z); //1 3

2. 활용

필요한 프로퍼티 값을 짧은 코드로 변수/상수에 담을 때

const array1 = [1, 2, 3, 4, 5];

// const length = array1.length;
const { length } = array1;

console.log(length); //5

 

함수 인자값의 가독성을 위해 객체를 사용할 때

// 인자가 많은 함수 - ⚠️ 좋지 않음!
function introduce(name, age, job, married) {
  console.log(`제 이름은 ${name}, `
    + `나이는 ${age}세구요. `
    + `직업은 ${job}, `
    + `${married ? '기혼' : '미혼'}입니다.`
  )
}

// 여러 인자, 순서 중요 - 가독성 떨어짐
introduce('김철수', 28, '개발자', false);

인자도 많고 가독성이 엄청 떨어진다. 가독성 좋게 만든 코드는 다음과 같다.

// 인자를 하나의 객체로 묶어 받음 
function introduce(person) {
  console.log(`제 이름은 ${person.name}, `
    + `나이는 ${person.age}세구요. `
    + `직업은 ${person.job}, `
    + `${person.married ? '기혼' : '미혼'}입니다.`
  )
}

// 가독성 좋음, 프로퍼티명만 제대로 입력하면 순서 무관
const person1 = {
  job: '개발자',
  age: 28,
  married: false,
  name: '김철수',
  blood: 'O' // 추가 인자 무관
};

introduce(person1);

introduce함수에 인자를 여러개 받는 것이 아니라 person이라는 객체를 받게끔 했다. 이렇게 하면 순서도 상관이 없고 관리도 편하며 추가 인자를 넣어도 오류를 일으키지 않는다. 

 

다른 방식으로 디스트럭쳐링을 활용한 코드는 다음과 같다.

// 디스트럭쳐링 (적절히 활용)
function introduce({age, married, job, name}) {
  // 순서 무관
  // 이 프로퍼티들을 갖는 객체를 인자로 받겠다는 의도 드러냄

  console.log(`제 이름은 ${name}, `
    + `나이는 ${age}세구요. `
    + `직업은 ${job}, `
    + `${married ? '기혼' : '미혼'}입니다.`
  )
}

const person1 = {
  job: '개발자',
  age: 28,
  married: false,
  name: '김철수',
  blood: 'O'
};

introduce(person1);

보면 introduce함수 인자를 받는 부분에 {}로 객체 안에 있는 프로퍼티들을 선언을 했다. 이것이 이 {}안에 있는 프로퍼티들을 갖는 객체를 인자로 받겠다는 뜻이다. 

디스트럭쳐링으로 이렇게 개발자의 의도를 명확하게 드러낼 수도 있다.