💡 들어가며
Map과 Set도 결국에는 객체, 그리고 이터러블 객체로 취급된다는 것을 기억하자!
또한 Map,Set은 ES6에서 새롭게 추가된 문법이다!
let map = new Map();
// ✅ 문자, 숫자, 불린형 키 모두 가능
map.set('1', 'str1');
map.set(1, 'num1');
map.set(true, 'bool1');
// ✅ 객체는 키를 문자형으로 변환하지만 맵은 키의 타입을 변환시키지 않고 그대로 유지
alert( map.get(1) );
alert( map.get('1') );
alert( map.size ); // 3
let john = { name: "John" };
let visitsCountMap = new Map();
visitsCountMap.set(john, 123);
alert( visitsCountMap.get(john) ); // 123
💡 map[key]와 같이 사용할 수는 있지만 이 방법은 map을 일반 객체처럼 취급하기에 map을 사용할 때는 전용메서드인 get,set을 사용하자.
💡 map.set을 호출하면 set하고 난 맵 자신을 반환한다. 이에 따라 map.set을 체이닝할 수 있다.
map.set('1', 'str1') .set(1, 'num1') .set(true, 'bool1');
map.keys()
: 각 요소의 key
를 모은 iterable
객체 반환 map.values()
: 각 요소의 value
를 모은 iterable
객체 반환map.entries()
: 요소의 키와 값을 을 한 쌍으로 하는 iterable
객체 반환 let recipeMap = new Map([
['cucumber', 500],
['tomatoes', 350],
['onion', 50]
]);
// ✅ map.keys()
for (let vegetable of recipeMap.keys()) {
alert(vegetable); // cucumber, tomatoes, onion
}
// ✅ map.values()
for (let amount of recipeMap.values()) {
alert(amount); // 500, 350, 50
}
// ✅ map.entries()
for (let entry of recipeMap) {
alert(entry); // cucumber,500 ...
}
💡 map은 배열과 유사하게 forEach도 지원한다.
recipeMap.forEach( (value, key, map) => { alert(`${key}: ${value}`); // cucumber: 500 });
let map = new Map([
['1', 'str1'],
[1, 'num1'],
[true, 'bool1']
]);
alert( map.get('1') ); // str1
Object.entries(obj)
사용해서 객체의 키-값 쌍을 요소([key, value])로 가지는 배열을 반환받는다! (map을 이터러블 객체로 바꾸는 map.entries()와 다름!)객체를 배열로 바꾸고, map에 넣어주기 때문에 결국 1번과 같다!
Object.entries(obj)
: 객체의 키-값([키,값]) 쌍을 요소로 가지는 배열을 반환한다.
let obj = {
name: "John",
age: 30
};
// ✅ [ ["name","John"], ["age", 30] ]를 map에 넣어준다!
let map = new Map(Object.entries(obj));
alert( map.get('name') ); // John
Object.fromEntries
: 각 요소가 [키-값]인 이터러블 객체(배열 등)을 객체로 바꿔준다!let map = new Map();
map.set('banana', 1);
map.set('orange', 2);
map.set('meat', 4);
//✅ map을 이터러블 객체로 바꾸고, 그 객체를 일반 객체로 바꾼다!
// ✅ fromEntries는 이터러블 객체를 인자로 받기에 그냥 map만 넣어줘도 동일하게 동작한다!
let obj = Object.fromEntries(map.entries());
// 맵이 객체가 되었습니다!
// obj = { banana: 1, orange: 2, meat: 4 }
alert(obj.orange); // 2
key
가 없는 값이 저장된다. map
과 다르게 요소 추가를 위해서는 add
메서드를 사용한다. map
과 동일하게 keys,values,entries를 이용해서 반복작업을 수행할 수 있다. 💡 Set에는 key가 없는데? keys를 어떻게 이용하지?
set.keys()와 set.values()는 동일한 작업을 한다. 둘 다 셋 내의 모든 값을 포함하는 이터러블 객체를 반환한다.
하지만 map과의 호환성을 위해 두 가지 모두 존재한다!
forEach도 map에서value, key, map
세 가지 인수를 받을 수 있기 때문에 set에서도value, valueAgain, set
이렇게 첫번째 인자와 동일한 두번째 인자를 받아서 세 가지 인수를 받는다!
모두 호환성을 위한 것이다!
let set = new Set();
let john = { name: "John" };
let pete = { name: "Pete" };
let mary = { name: "Mary" };
// john, mary는 여러 번 방문
set.add(john);
set.add(pete);
set.add(mary);
set.add(john);
set.add(mary);
// Set에는 유일무이한 값만 저장됩니다.
alert( set.size ); // 3
for (let user of set) {
alert(user.name); // // John, Pete, Mary
}
이 세가지 메서드가 map.keys()
, map.values()
, map.entries()
와 다른 부분은 무엇일까?
obj.keys()
가 아닌 Object.keys(obj)
를 호출한다data.keys()
라는 메서드를 구현하는 경우가 있을 수 있다. (객체 요소에는 함수도 들어갈 수 있으니까!)Object.keys(obj)
를 사용하면 충돌없이 커스텀 메서드와 내장 메서드를 모두 사용할 수 있기에 Object.keys(obj)
를 호출한다. Object.*
를 호출하면 iterable 객체가 아닌 객체의 한 종류인 배열
을 반환한다. let user = {
name: "John",
age: 30
};
Object.keys(user); // ["name", "age"]
Object.values(user); // ["John", 30]
Object.entries(user); // [ ["name","John"], ["age",30] ]
객체에 배열 전용 메서드를 적용해 변환하고 싶은 경우 다음과 같은 절차를 거치면 된다.
let prices = {
banana : 1,
lemon : 2,
cherry : 3,
}
let doublePrices = Object.fromEntries(Object.entries(prices).map(([key,value])=> [key, value *2]));
alert(doublePrices.cherry); // 6
split
과 같이 반환값이 배열인 메서드를 함께 사용해도 좋다. let [firstName, surname] = "Bora Lee".split(' ');
// ✅ 두번째 요소 무시
let [firstName, , title] = ["Matthew", 22, "Boys Planet", "Canada"];
alert( title );
let [one, two, three] = new Set([1,2,3]);
let user ={};
[user.firstName, user.lastName] = "Bora Lee".split(' ');
alert(user.name); // Bora
let guest = "Jane";
let admin = "Pete";
[guest, admin] = [admin, guest];
alert(`${guest} ${admin}`); // pete Jane
let [firstName, age, ...rest] = ["Matthew", 22, "Boys Planet", "Canada"];
alert(firstName); //Matthew
alert(age); //22
alert(rest[0]);//Boys Planet
let [firstName, surname] = [];
alert(firstName); // undefined
alert(surname); // undefined
=
를 사용해 할당할 값이 없을 경우의 기본값을 지정할 수 있다. let [name = "Guest", surname = "Anonymous"] = ["Matt"];
alert(name); // Matt (배열에서 받아온 값)
alert(surname); // Anonymous (기본값)
// ✅ 복잡한 표현식이나 함수 호출도 기본값이 될 수 있다.
let [name = prompt("이름을 입력하세요"), surname = prompt("성을 입력하세요")] = ["Matt"];
alert(name); // Matt
alert(surname); // 유저가 입력한 값
let options = {
title: "Menu",
width: 100,
height: 200
};
let {title, width, height} = options;
//✅ 순서가 바뀌어도 동일하게 동작한다.
//let {height, width, title} = options;
alert(title); // Menu
alert(width); // 100
alert(height); // 200
let {width: w, height: h, title} = options;
alert(w); // 100
alert(h); //200
alert(title); //Menu
let options = {
age : 22
}
let {name = "Guest", age : a, gender : g = undefined} = options;
alert(name); //Guest
alert(a); //22
alert(g); //undefined
let options = {
title: "Menu",
width: 100,
height: 200
};
let {title, ...rest} = options;
// ✅ rest : { width: 100, height: 200 }
alert(rest.height); //100
alert(rest.width); //200
💡 let 없이 사용하기
지금까지는let {title, ...rest} = {...}
이렇게 사용했는데 만약 let으로 새로운 변수를 선언하지 않고 이미 존재하는 변수에 값을 할당하고 싶다면?let title, width, height; //✅ 다음과 같이 쓰면 에러가 발생한다! (SyntaxError: Unexpected token '=') {title,width,height} = { title: "Menu", width: 100, height: 200};
alert(title);
자바스크립트는 표현식(값으로 평가될 수 있는 statement [참고](https://velog.io/@dolarge/JavaScript-%ED%91%9C%ED%98%84%EC%8B%9D%EA%B3%BC-%EB%AC%B8)) 안에 있지 않으면서 주요 코드 흐름 상에 있는 {...}을 코드 블록으로 인식한다.
따라서 `{title,width,height}`를 코드 블록으로 인식해서 에러가 발생한 것이다.
다음과 같이 할당문을 괄호로 감싸 코드 블록이 아닌 표현식으로 인식하게 하면 에러가 발생하지 않는다.
```js
let title, width, height;
//✅
({title,width,height} = { title: "Menu", width: 100, height: 200});
alert(title);
let options = {
size: {
width: 100,
height: 200
},
items: ["Cake", "Donut"],
extra: true
};
let {
size: { // size는 여기,
width,
height
},
items: [item1, item2], // items는 여기에 할당함
title = "Menu" // 분해하려는 객체에 title 프로퍼티가 없으므로 기본값을 사용함
} = options;
함수의 매개변수를 선택적으로 사용하는 상황이 생겼다.
function showMenu(title = "Untitled", width = 200, height = 100, items = []) {
}
다음과 같은 함수에서 기본값을 사용해도 되는 경우에는 함수를 이렇게 호출해야한다.
showMenu("My Menu", undefined, undefined, ["Item1", "Item2"])
undefined를 여러개 넘겨주는 것이 지저분해보이고, 가독성도 떨어진다.
이 경우 구조분해 할당을 이용하면 좋다.
let options = {
title: "My menu",
items: ["Item1", "Item2"]
};
//✅ 매개 변수를 객체로 모아 함수에 전달한다.
function showMenu({title="Untitled", width:w=200, height=100, items=[]}){
alert( `${title} ${w} ${height}` ); // My Menu 200 100
}
//✅ undefined를 명시하지 않아도 초깃값 할당이 가능하다!
showMenu(options);
💡만약 모든 변수에 초깃값을 할당하고 싶다면?
showMenu();
이 아니라showMenu({});
처럼 빈괄호를 명시적으로 넘겨줘야한다.
이게 조금 귀찮다면 인수 전체의 기본값을 만들어줄 수 있다.function showMenu({ title = "Menu", width = 100, height = 200 } = {}) { alert( `${title} ${width} ${height}` ); } showMenu(); // Menu 100 200