Development/Etc

[모던 자바스크립트] Object 기깔나게 사용하기

bbubbush 2022. 9. 8. 21:44

들어가며

자바스크립트에서 맵(Map)은 ES6가 되어서야 등장했다. 다른 언어에 비하면 상당히 늦은 편이다. 왜일까? 바로 객체(Object)라는 대안이 있었기 때문이다. 따라서 맵을 어떻게 사용하는지 알아가는 것도 좋지만, 그전부터 맵을 대신하던 객체를 어떻게 기깔나게 사용할 수 있는지 파악하는 것이 더 중요하다는 생각이 들었다. 그래서 이번에는 객체에 대해 자세히 알아보려고 한다.

순서는 맵과 객체의 차이를 간단히 살피고, 기존의 객체 사용 방식을 어떻게 개선된 방법으로 사용할 수 있는지 비교하며 설명하면서 진행된다.

 

객체와 맵의 차이

두드러지는 차이는 키의 타입이다. 객체는 오로지 문자열만 키로 사용할 수 있고, 맵은 모든 데이터 타입을 사용할 수 있다.

const sampleFunc = () => {
  console.log('Hello JS!');
}

const sampleMap = new Map();
sampleMap.set('str', '키가 문자열 타입이다');
sampleMap.set(100, '키가 정수 타입이다');
sampleMap.set(false, '키가 불리언 타입이다');
sampleMap.set(sampleFunc, '키가 함수다');

console.log(sampleMap.get('str'));      // '키가 문자열 타입이다'
console.log(sampleMap.get(100));        // '키가 정수 타입이다'
console.log(sampleMap.get(false));      // '키가 불리언 타입이다'
console.log(sampleMap.get(sampleFunc)); // '키가 함수다'

그 밖에 Iteration interface 사용, 조회 속도, 데이터 입력 순서 보장 등의 차이가 있지만, 실무적인 관점에서 데이터가 특별히 많아 조회 시간이 오래 걸리는 상황이거나, 이터러블을 사용해야 하는 상황이 아니면 큰 의미가 없어 객체가 주로 사용되게 된다.

복잡한 내용은 차치하고, 한 줄로 요약하면 다음과 같다.

“ 값의 데이터 타입이 다양하다면 객체를 써라! “

 

1. 데이터 할당

보통의 팝업을 호출하는 코드가 있다. 정확히는 팝업의 파라미터를 전달하기 위해 세팅하는 코드다.

const popupId = 'POP01';
const popupData = {id: '1', name: 'JavaScript'};
const popupCallback = function (res) {
  console.log(res);
}
const popupParam = {
  popupId: popupId,
  popupData: popupData,
  popupCallback: popupCallback
}

대게 키와 동일한 이름의 변수를 사용하기 때문에 꽤 자주 발생하는 상황이다. 이와 같이 빈도 높은 코드를 편하게 작성할 수 있도록 모던 자바스크립트에서는 아래와 같은 문법을 지원한다.

const popupId = 'POP01';
const popupData = {id: '1', name: 'JavaScript'};
const popupCallback = function (res) {
  console.log(res);
}
const popupParam = {
  popupId,
  popupData,
  popupCallback
}

키와 동일한 이름의 변수를 세팅할 때 콜론(:)을 생략할 수 있다. 이를 ‘프로퍼티 단축’이라고 한다. 물론 기존의 방식과 혼용해서 써도 문제없다.

 

2. 동적인 키 생성

개발하다 보면 가끔 동적으로 키를 생성할 때가 있다. 예를 들면 아래와 같다.

const obj = {};  
for (let i = 0; i < 10; i++) {
  obj['id_' + i] = '데이터 세팅' + i;
}

위와 같이 변수를 선언 후 키를 동적으로 생성하여 사용하는 방식이 주로 사용되었다. 다만 변수의 선언과 동시에 동적인 키를 할당하면 오류가 발생하게 된다.

현재는 이 부분을 개선하여 아래와 같은 형태로 코드를 작성할 수 있게 되었다.

const dynamicPopupId = 'popupId';      
const popupParam = {
  [dynamicPopupId]: '동적 아이디',
  [dynamicPopupId + '_01']: '동적 아이디 01',
  [`${dynamicPopupId}_02`]: '동적 아이디 02'
}

동적으로 키를 생성하는 방식이 아무래도 데이터에 의존하게 되어 좋은 방법이 아니기에 자주 사용되지는 않는다. 그래도 알고 안 쓰는 것과 몰라서 못쓰는 것은 차이가 있으니 이런 방법도 가능하다고 참고만 하면 된다.

 

 

반응형

 

3. 전개 연산자

두 객체의 정보를 하나로 합쳐야 할 때, 보통 아래와 같이 직접 값을 매핑해줘야 한다.

const loginUserInfo = {
  id: 1,
  name: '홍길동',
  email: 'bbubbush@gmail.com'
}
const loginUserDeptInfo = {
  deptId: 10,
  deptName: '인사팀'
}

const mergeLoginUserInfo = {
  id: loginUserInfo['id'],
  name: loginUserInfo['name'],
  email: loginUserInfo['email'],
  deptId: loginUserDeptInfo['deptId'],
  deptName: loginUserDeptInfo['deptName']
}

아마 실무에서 이런 상황을 마주했다면 loginUserInfo 객체에 loginUserDeptInfo의 정보를 덕지덕지 붙여 사용했을 것이다. 가장 간단하고 편한 방법이기는 하지만 객체의 불변성이 깨지고, 실행되는 위치에 따라 정보가 달라지므로 버그를 만들 확률이 늘어난다.

ES6부터 전개 연산자를 통해 이런 불편함을 덜어낼 수 있다. 아래 코드는 위의 코드와 동일하게 동작한다.

const mergeLoginUserInfo = {
  ...loginUserInfo,
  ...loginUserDeptInfo
}

만약 동일한 키를 사용한다면, 전개 연산자를 늦게 사용한 객체의 정보로 덮어지므로 주의해야 한다.

 

4. 구조 분해 할당(비 구조화)

프로젝트를 하면 공통으로 사용하는 팝업을 사용하는 경우가 빈번하다. 혼자 사용하는 것이 아니다 보니 불필요한 정보도 같이 받게 된다. 아래 예제 코드를 보자.

function popupCallback(response) {
 if (response['data']) {
   const result = response['data'];
   document.getElementById('userName').value = result['userName'];
 } 
}

원하는 값은 response[’data’] 안에 있어서 매번 한 번의 depth를 들어가서 데이터를 가져와야 한다. 애초에 response[’data’]만 보내달라고 하자니 모두 사용하기 때문에 쉽게 수정할 수 없다.

이럴 때 객체의 구조 분해 할당을 이용할 수 있다. 코드를 먼저 보자.

function popupCallback({ data }) {
  document.getElementById('userName').value = data['userName'];
}

구조 분해 할당은 중괄호 안에 내가 사용할 키의 이름으로 변수를 넣어두면, 자동으로 같은 키의 값을 찾아서 넣어준다.

만약 데이터를 담고 있는 response[’data’] 뿐만 아니라 조회가 성공적으로 되었는지 알려주는 response[’isSuccess’] 라는 값도 필요하다면 이렇게 사용하면 된다.

function popupCallback({ data, isSuccess }) {
  if (isSuccess) {
    document.getElementById('userName').value = data['userName'];  
  }
}

말 그대로 객체의 구조를 분해해서 변수에 재할당해주는 기능을 뜻한다. 실용적이어서 자주 사용하게 되는 문법이다. 참고로 배열도 동일하게 사용할 수 있다.

 

5. 트레일링 콤마(Trailing comma)

객체의 속성을 복사+붙여 넣기 하면서 꽤나 귀찮게 하는 문제가 있다. 바로 쉼표다. 코드를 보자.

const userInfo = {
  id: 1,
  name: '홍길동'
  email: 'bbubbush@gmail.com'
}

위 코드는 오류가 난다. name 필드 뒤에 쉼표가 없기 때문이다. 똑똑한 IDE를 사용한다면 미리 알려주겠지만, 런타임 시점에 확인되는 경우도 많다. 그러면 짜증 한 번 내고 쉼표를 넣고 다시 새로고침 한다.

과거부터 이 문제를 개선하기 위한 노력은 꾸준히 있었다. 생각해보자. ‘보통 가장 마지막 줄을 복사해서 쓰니깐 이것에 최적화된 문법으로 짜면 되지 않을까?’

그 결과가 이런 구조의 코드를 만들었다.

const userInfo = {
  id: 1
  , name: '홍길동'
  , email: 'bbubbush@gmail.com'
}

이런 코드라면 맨 아래줄을 복사해도 쉼표가 빠지는 경우가 없다. 비록 보기에 안 좋지만 개발단계의 실수를 줄여주므로 결과적으로 개발 속도를 향상해준다.

ES6부터는 이럴 필요 없이 쉼표를 그대로 포함시켜서 개발할 수 있도록 트레일링 콤마 기능을 지원한다.

const userInfo = {
  id: 1,
  name: '홍길동',
  email: 'bbubbush@gmail.com',
}

그냥 쉼표를 맨 뒤에 계속 붙이면 된다. 다음 키-값 정보가 없으면 알아서 마지막 데이터라고 인식한다. 가독성과 실용성 모두 잡은 좋은 개선방안이다.

 

마치며

이번에는 기깔나게 객체를 다루는 방법을 살펴봤다. 각 기능의 자세한 설명은 Mozilla의 Object prototype을 참고하면 된다. 객체는 자주 사용하는 자료구조인 만큼 변경사항을 실무에 적용하기 좋다. 바로 적용해보자. 빨리 익숙해질수록 내가 더 편해지게 된다.

 

 

 

[모던 자바스크립트 관련 글]

 

[모던 자바스크립트] var를 사용하지 않아야 하는 이유

2022.09.03 - [Development/Etc] - [모던 자바스크립트] var를 사용하지 않아야 하는 이유 들어가며 ES6에서는 변수를 사용하기 위해 새로운 문법인 let과 const를 지원하면서 동시에, var의 사용을 지양하라고

bbubbush.tistory.com

 

[모던 자바스크립트] Array 스마트하게 사용하기

들어가며 배열(Array)은 맵과 함께 데이터를 관리하기 위한 가장 효율적인 자료구조다. 이번에는 배열로 무엇을 할 수 있는지 보면서 for 구문의 지옥에서 벗어날 수 있는 것을 목표로 한다. 고전

bbubbush.tistory.com

 

[모던 자바스크립트] 어썸한 Funtion 변경사항

들어가며 자바스크립트는 함수로 대표된다고 해도 과언이 아니다. 이제는 객체지향적인 방식으로 작업하는 개발자도 많지만 과거부터 함수를 정의하고 사용해왔기에 아직까지 함수 지향적인

bbubbush.tistory.com

 

[모던 자바스크립트] Promise 한 방에 뿌수기

들어가며 아마 ES6의 내용 중 이해하기 가장 어려운 내용이 프로미스가 아닐까 생각한다. 다른 변경사항은 기능에 충실한 반면, 프로미스는 특정한 상황을 해결하기 위해 등장했기 때문이라 생

bbubbush.tistory.com

 

[모던 자바스크립트] 이름은 Optional, 적용은 Required

들어가며 ES6부터 객체의 값을 안정적으로 가져오는 옵셔널이 도입됐다. 개념도 쉽고 적용하기도 쉽기 때문에 활용도가 높다. 더 이야기할 게 없으니 바로 알아보자 🙂 전통적인 객체 프로퍼티

bbubbush.tistory.com