구조분해할당에 대해

하준수·2023년 7월 9일

javascriptSyntax

목록 보기
1/4
post-thumbnail

한줄 요약: 객체로 선언해서 export했으면, import 할 때도 객체로 불러와야 함.

왜 이 글을 쓰는가

레이어드 패턴에서 함수선언이 제대로 되지 않았음. → 멘토에게 질문했으나, 곧바로 "구조분해할당 공부 안했죠?" 피드백 들음.

// 잘못쓴것
// dataSource.js
const { DataSource } = require("typeorm");
const appDataSource = new DataSource({
  type: process.env.DB_CONNECTION,
  host: process.env.DB_HOST,
  port: process.env.DB_PORT,
  username: process.env.DB_USERNAME,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_DATABASE,
});
module.exports = { appDataSource };

// productDao.js
const appDataSource = require("./dataSource");
const lookupAllProducts = async () => {
  try {
    return await appDataSource.query(
      `SELECT
      id,
      name,
      price,
      category_id,
      description,
      thumbnail_image,
      hover_image,
      detail_information
    From products`
    );
  } catch {
    const error = new Error("dataSource Error");
    error.statusCode = 400;
    throw error;
  }
};
// 중략
// appDataSource.query가 function이 아니라는 에러 출력

뭐가 잘못되었는지 아시겠나요?

구조분해할당 구문

구조분해문법 || Destructuring Assignment

구조 분해 할당 구문은 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식입니다.
사실 위 링크가 이 포스팅보다 더 값지고 유익하다.
배열 또는 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 자바스크립트 표현식이라고 한다. 함수에 객체나 배열을 전달해야 하는 경우, 또는 객체나 배열에 저장된 데이터 전체가 아닌 일부만 필요한 경우 해당 객체나 배열을 변수로 분해할 수 있게 해주는 것이 구조분해할당.


배열에서의 예시

const arr = [1, 2, 3];
const [a, b, c] = arr;
console.log(a);  // 1
console.log(b);  // 2
console.log(c);  // 3

→ 2째 줄에서 배열 arr의 요소들을 각각 변수 a, b, c에 할당시켜줌. 그러니까 두번째 줄은 아래와 같은 선언이 압축되어 있는 것임.

const a = arr[0];
const b = arr[1];
const c = arr[2];

객체에서의 예시

const obj = { name: 'xxx', age: 100 };
const { name, age } = obj;
console.log(name);  // 'xxx'
console.log(age);   // 100

→ 2째 줄에서 각각의 키들과 그 값들을 name과 age라는 변수로 선언.
그러니까 두번째 줄은 아래와 같은 선언이 압축되어 있는 것임.

const name = obj.name;
const age = obj.age;

- 주의사항: 객체 구조분해할당 시 중요한 것은 변수로 지정해 주는 값이 키값과 같아야 한다. 별도로 키값을 따로 설정해주려면 아래와 같은 절차가 필요하다. 키값을 찾을 수 없으면 undefined가 된다.

const obj = { name: 'xxx', age: 100 };
const { name: notName, age: notAge } = obj;
console.log(notName);  // 'xxx'
console.log(notAge);   // 100

중첩구조분해

배열 객체의 중첩된 요소에서도 적용 가능하며, 필요한 속성만 선택해 할당할 수도 있다.

const data = {
  name: 'John Doe',
  age: 30,
  address: {
    city: 'New York',
    country: 'USA'
  },
  hobbies: ['reading', 'traveling', 'cooking']
};
// 객체의 중첩된 요소 구조 분해 할당
const { name, age, address: { city, country }, hobbies: [hobby1, hobby2, hobby3] } = data;

console.log(name);      // 'John Doe'
console.log(age);       // 30
console.log(city);      // 'New York'
console.log(country);   // 'USA'
console.log(hobby1);    // 'reading'
console.log(hobby2);    // 'traveling'
console.log(hobby3);    // 'cooking'

→ 만약 구조분해할당 없이 각 변수들을 지정해줘야 했다면 아래와 같았을 것이다.

const name = data.name;
const age = data.age;
const city = data.address.city;
const country = data.address.country;
const hobby1 = data.hobbies[0];
const hobby2 = data.hobbies[1];
const hobby3 = data.hobbies[2];
//어후 끔찍해;;

자, 왜 이걸 쓰는지 아시겠죠?

1. 코드 가독성, 간결성(유지보수성): 변수할당하는 프로세스가 한줄로 간단히 끝난다.
2. 변수 이름 통일성: 변수 이름을 원하는 대로 지정할 수 있다.
3. 중첩된 구조 처리: 중첩된 객체나 배열의 요소를 간단하게 추출 가능하다. 복잡한 데이터 구조를 다룰 때 유용하다.

그래서, 어떻게 활용할까?

일단 지금 당장 생각나는 활용처는 다음과 같다.
1. 다른 곳에서 객체형태로 정의한 함수를 소환할 때, 객체로 소환해야함.
2. 특히 typeorm을 사용하여 dao레벨에서 데이터를 추출해 낸 경우, 추출해 낸 데이터 그 자체는 배열로 감싸여 나오기 때문에, 쿼리문을 선언할 때 배열로 감싸 선언해 주면 리턴값으로 배열은 벗겨낸 데이터로 정제해 낼 수 있다. 그렇게 한다면 dao에서 추출한 데이터를 서비스 레벨로 넘겨 활용할 때, 해당 데이터가 배열이 아닌 전제 하에 비즈니스 로직을 작성할 수 있게 된다.

0개의 댓글