변수 선언은 단지 선언의 기능만을 하는게 아닌, 의도를 전달해야 한다.
내가 Javascript
를 공부하며 깨달았던 중요한 사실 중 하나는 이거다.
이전 이제는 모던 자바스크립트를 알아야지 (let-const 편) 게시물에서도 한번 이야기 했다시피, 선언은 의도를 전달 할 수 있어야 한다.
이는 컬렉션
을 만들때도 동일하게 적용된다.
모던 자바 스크립트에서는 기존의 Object(객체)
이외에 Map(맵)
과 Set(세트)
라는 컬렉션이 추가됐다.
이번에는 이것이 무엇인지, 왜 추가 되었는지, 어떻게 사용해야 하는지에 대해 알아보도록 하자.
배열이 있는데 객체는 뭐하러 쓰는거죠?? 🤔
Javascript
에서 데이터를 저장 하는 방법은 정말 많다.
많이 사용되는 것 중 하나는 Array(배열)
인데, 순서가 중요하지 않은 데이터의 경우 오히려 더 복잡해 질 수 있다.
말로하면 잘 이해가 안되니 예제를 보며 진행해보자.
만약 가상의 (로그인, 로그아웃, 회원가입) 3가지 종류의 인증키를 배열로 저장해 놓은 코드가 있다고 가정해보자.
const keys = ['DORHNJ#!IRAFD', '123!@I#JNF', '!$OMJFDQFfvdsf'];
과연 개발자는 이 코드를 보고 123!@I#JNF
가 어디에서 사용하는 인증키인지 알 수 있을까?
누구에게 물어보지 않는 이상 쉽지 않을 것이다.
그렇다고 123!@I#JNF
인증키가 들어가야 하는 곳에 !$OMJFDQFfvdsf
를 넣는것도 안될 것이다.
이 처럼 이 데이터는 순서가 상관 없으며
, 다른 값이 뭔지 상관 없고
, 데이터가 교체되면 안된다
는 3가지 특징을 가진다.
이 경우 Key-Value 중 객체
를 사용하면 된다.
위 예제 코드를 객체
로 바꾸어 표현하면 아래와 같다.
const keys = {
login : 'DORHNJ#!IRAFD',
logout : '123!@I#JNF',
join : '!$OMJFDQFfvdsf'
};
이제 각 값을 얻으려면 몇 번째의 값이 어떤 값인지 찾아 볼 필요가 없다.
login
인증 키를 얻고 싶다면 keys.login
또는 keys['login']
으로 값을 참조 할 수 있다.
console.log(keys.login);
// output : DORHNJ#!IRAFD
이 같은 방법은 별 거 아니어 보이지만, 훨신 직관적이고 사용하기가 쉽다.
때문에 거의 대부분의 개발 과정에서 객체
를 가장 많이 사용한다.
ㅎㅎ 그럼 이제 뭐든지 객체로 만들면 되겠네요! 😊
결론부터 말하자면 된다.
하지만 그게 전부라면 이 게시글을 작성하지도 않았을 것이다.
조금 더 정확히 말하자면... 가능하긴 하다.
( 그 외에도 되긴된다, 할수야 있다, 추천하진 않는다 등이 있다...)
이전에 템플릿 리터럴에 대해 설명하며 아래와 같은 말을 한 적 있다.
문자열 조합에 정답은 없고, 여러 기능 중 상황을 고려해 가장 적합한 것을 사용해야 한다.
이는 사실 모든 방면에 해당 된다.
모든 정보를 객체로 만드는 것이 '안된다'라고 할 수 없으나,
경우에 따라 '더 좋은 방법이 있다'라고는 할 수 있다.
모던 자바 스크립트에서 Map
과 Set
이 탄생한 이유이다.
(이 Map 아님)
MDN에는 Map
의 장점과, 컬렉션 선택을 객체
로 할지 Map
으로 할지에 대해 간단히 서술되어 있다.
자세한 내용을 서술하기에는 너무 길어서, 나중에 따로 포스팅 할 예정이다.
Map 의 장점
1.객체
의 Key는strings
지만,Map
의 Key는 모든 값을 가질 수 있다.
2.객체
는 수동으로 크기를 추적해야 하지만,Map
은 크기를 쉽게 알 수 있다.
3.Map
은 삽입된 순서대로 반복된다.
4.객체
에는 prototype 이 있어Map
에 기본 키들이 있다.
객체 또는 Map을 결정하는 사항
Map
: 실행 시 까지 키를 알 수 없고, 모든 키가 동일한 type이며 모든 값들이 동일한 type 일 때객체
: 각 개별 요소에 대해 적용해야 하는 로직이 있을 때
요약하자면 경우에 따라 객체
만 사용하기엔 불편한 점이 있어서 이를 보완하고자 Map
을 사용한다는 것이다.
이 내용을 기반으로 Map
을 어떤 경우에 쓰는지 자세히 알아보자.
나는 예시 중 하나로 데이터 변경이 잦은 정보에 Map
을 사용하는 이유에 대해 적어보려 한다.
실제 개발에서 '데이터 변경이 잦은'정보라 하면 뭐가 있을까?
대표적인 예로 쇼핑몰 등의 검색 사이트에서 필터링
이 있다.
실제로 개발을 안해봤어도 필터링
기능이 뭔지는 다들 알 것이다.
네이버 쇼핑을 예시로 한번 알아보자.
키보드를 찾고자 하는 모습이다.
하단을 보면 카테고리, 제조사, 키 방식 등등 많은 필터링
기능을 제공하는 것이 확인된다.
네이버 쇼핑의 검색 정보가 아래와 같다고 가정해보자.
const data = [
{
이름 : 'SPA-NKG1CU',
카테고리 : '유선키보드',
제조사 : '삼성전자',
키방식 : '기계식',
접점방식 : '청축',
},
{
이름 : 'GK898B',
카테고리 : '무선키보드',
제조사 : '한성컴퓨터',
키방식 : '무접점(광축)',
접점방식 : '광축(클릭)',
},
]
필터링
할 내용을 저장 할 빈 객체
를 하나 만든다.
그리고 '필터링 목록 추가', '필터링 목록 삭제', '필터링 목록 초기화' 기능을 만들어준다.
// filters 빈 객체 생성
let filters = {};
// 필터링 목록 추가
const addFilters = (filters, key, value) => {
filters[key] = value;
};
// 필터링 목록 삭제
const removeFilters = (filters, key) => {
delete filters[key];
};
// 필터링 목록 초기화
const clearFilters = (filters) => {
filters = {};
return filters;
}
완벽한데요! 객체를 써도 문제 없겠어요. 🤗
라고 생각했다면 모던 자바 스크립트에는 맞지 않다.
물론 기능 자체는 잘 돌아가지만 이상한 부분이 있다.
필터링
목록을 조작하는 추가
, 삭제
, 전체삭제
3가지 기능이 존재하는데 그 동작 방법이 모두 다르다는 것이다.
이게 무슨 말일까? 좀 더 자세히 알아보자.
- 추가 :
[key]
를 이용- 삭제 :
delete
를 이용- 전체삭제 : 변수 재할당 (
new Object()
)를 이용
이제 좀 보이는가?
이는 예측 불가하고 명확하지 않은 코드를 야기시킨다.
우리는 단순히 돌아가는 코드를 찍어내는게 중요한 게 아니다.
최대한 예측 가능한 코드를 만들어 개발 속도를 높이고, 읽는 시간을 줄여야 한다.
Map
에서는 이를 보완하기 위해 전용 메서드
가 존재하는 등 예측이 가능하도록 했다.
한번 Map
을 이용해서 다시 개발해보자.
이번엔 Map
으로 filters
를 선언해보자.
Map
은 new Map();
으로 선언 할 수 있다.
let filters = new Map();
그리고 데이터를 추가하려면 set()
메서드를 사용한다.
인자값은 두 개가 전달되며, 순서대로 key
, value
이다.
filters.set('이름', 'SPA-NKG1CU');
체이닝을 사용하면 새 Map
을 생성하고 바로 데이터를 추가할 수 있다.
let filters = new Map()
.set('이름', 'SPA-NKG1CU')
.set('카테고리', '유선키보드')
.set('제조사', '삼성전자')
.set('키방식', '기계식')
.set('접점방식', '청축');
또는 배열을 통해 작성 또한 가능하다.
let filters = new Map(
[
['이름', 'SPA-NKG1CU'],
['카테고리', '유선키보드'],
['제조사', '삼성전자'],
['키방식', '기계식'],
['접점방식', '청축'],
]
);
Map
의 데이터를 key
로 가져오려면 get()
메서드를 사용하면 된다.
filters.get('이름');
Map
의 데이터를 제거하려면 delete()
메서드를 사용한다.
filters.delete('이름');
filters.get('이름');
마지막으로, Map
의 모든 데이터를 삭제하려면 clear()
메서드를 사용한다.
filters.clear();
filters.get('이름');
자, 그럼 이제 위에서 만들었던 필터링
목록을 조작하는 추가
, 삭제
, 전체삭제
기능을 Map
으로 만들어보자.
const filters = new Map();
// 필터링 목록 추가
const addFilters = (filters, key, value) => {
filters.set(key,value);
};
// 필터링 목록 삭제
const removeFilters = (filters, key) => {
filters.delete(key);
};
// 필터링 목록 초기화
const clearFilters = (filters) => {
filters.clear();
}
훨신 깔끔해 진 모습이 보여진다.
이게 무슨 차이인가... 싶을 수도 있지만 실제 개발에서 이 같은 부분은 굉장히 큰 차이를 불러일으킨다.
Map
에 대한 사용 방법은 더 방대하지만, 일단 여기서는 기본 메서드만 알아보았다.
어떤가? 이제 Set
은 무엇일지 굉장히 기대되지 않는가.
바로 한번 알아보도록 하자.
Set
은 각 고유 항목을 하나만 갖는 간단한 컬렉션이다.
백문이 불여일견, 한번 예제를 통해 알아보자.
const data = [
{
이름 : 'SPA-NKG1CU',
카테고리 : '유선키보드',
제조사 : '삼성전자',
키방식 : '기계식',
접점방식 : '청축',
},
{
이름 : 'GK898B',
카테고리 : '무선키보드',
제조사 : '한성컴퓨터',
키방식 : '무접점(광축)',
접점방식 : '광축(클릭)',
},
{
이름 : 'SKG-3000UB',
카테고리 : '유선키보드',
제조사 : '삼성전자',
키방식 : '멤브레인',
접점방식 : '멤브레인',
},
];
아까 그 네이버 검색 예제가 다시 등장했다.
만약 이 데이터들의 제조사를 따로 수집하고 싶다면 어떻게 해야할까?
map()
메서드를 아는 사람들은 map()
으로, 모른다면 단순 for
반복문으로 가능할 것이다.
(위에서 알아본 Map
과 다른 것이다.)
// map()을 아는 사람
data.map(value=>value['제조사']);
// map()을 모르는 사람
let newData = new Array();
for(let i = 0; i < data.length; i++) {
newData.push(data[i].제조사);
}
실행결과 : ['삼성전자', '한성컴퓨터', '삼성전자']
실행결과는 위와 같다. 이게 우리가 원하던 실행 결과일까?
아니다. 삼성전자
, 한성컴퓨터
두 개만 보여져야 할 것이다.
그럼 중복된 값들을 걸러내는 로직이 추가되어야 겠다.
for
를 이용해 계속 작성해보자.
const getUnique = (element) => {
const newArray = new Array();
for(let i = 0; i < element.length; i++) {
if(!newArray.includes(element[i])) {
newArray.push(element[i]);
}
}
return newArray;
}
원했던 결과가 나타났다.
하지만 이번에는 과정이 너무 복잡해보인다.
이때 Set
을 이용하면 코드를 간단하게 바꿀 수 있다.
const 제조사 = ['삼성전자', '한성컴퓨터', '삼성전자'];
const newArray = new Set(제조사);
보다시피 어떠한 로직 없이 정리가 되었다.
그러나 한가지가 남았다. newArray
가 Array
가 아닌 Set
형식이다.
이를 스프레드 연산자를 활용해 변경할 수 있다.
const getUnique = (element) => {
return [...new Set(element)];
}
이제 그만...! 진짜 끝난거죠? 😥
이제 마지막이다.
위 코드는 매우 간결해졌지만, 우선적으로 data
배열을 모두 반복한 후 다시 분류하는 과정이 있다.
이 부분은 비효율적이므로 조금 더 최적화해보려 한다.
Set
또한 Map
과 동일한 기능을 제공하는 add()
, delete()
, clear()
메서드를 제공한다.
그리고 중복이 없는 Set
특성 상 이미 존재하는 데이터를 add
하면 무시한다.
우리는 이 특징을 이용할거다.
const uniqueCreater = (data) => {
const unique = new Set();
data.map((value) => {
unique.add(value.제조사);
});
return [...unique];
}
드디어 Set
을 이용해 원하는 속성을 한번에 중복 없이 분류하는 것에 성공했다.
reduce()
를 사용하면 이 코드에서 더 간단하게 하는 것도 가능하다.
사실 Map
과 Set
이외에 WeakMap
과 WeakSet
이라는 컬렉션도 존재한다.
이는 MDN에서 확인 가능하다.
이제 무조건 객체
로 만드는 것이 아닌, 상황에 따라 Map
, Set
을 적절하게 활용해
모던 자바 스크립트에 한 걸음 더 다가가보자.
객체
이외에 Map
과 Set
컬렉션도 사용한다.Map
은 데이터의 변경이 자주 일어날 때 사용한다.Set
은 데이터의 중복값을 걸러내야 할 때 사용한다.+ 읽어주셔서 감사합니다.
+ 오타, 내용 지적, 피드백을 환영합니다. 많이 해주실 수록 제 성장의 밑거름이 됩니다.
우연히 포스팅 보게 됫는 데, 정성이 들어간 글이네요
잘 읽었습니다!