1. Map오브젝트 형태, new Map()
Map 오브젝트
[Key / Value] pair collection
Map 오브젝트의 형태는 [key, value]형태로 대괄호 내에 key와 value를 작성합니다. 자바스크립트의 Map에서는 정말 다양형 타입을 key로 사용할 수 있는데 예제코드를 통해 알아봅니다.
cost obj = new Map([
["key", "value"],
[{book:200}, "오브젝트"],
[100, "Number"],
[Symbol(100), "symbol"]
]);
for(let keyValue of obj){
console.log(keyValue);
};
JavaScript
복사
[실행 결과]
["key", "value"]
[{book:200}, "오브젝트"]
[100, "Number"]
[Symbol(100), "symbol"]
⇒ key의 타입으로 String, Object, Number, Symbol 이 사용됩니다 또한 Map의 key처리는 for-of문을 통해 작성한 순서대로 읽어서 처리할수도 있습니다.
new Map()
new 키워드를 사용해 Map의 인스턴스를 생성할 수 있습니다. 파라미터에는 이터러블 오브젝트를 작성할 수 있는데 만약 생성시점에서 파라미터를 다 가지고있는게 아니라면 인스턴스 생성후 추가해주는 방향으로 사용할 수도 있습니다.
const obj = new Map([
["spring", "boot"],
["node", "js"]
]);
console.log(obj);
console.log(typeof obj);
JavaScript
복사
[실행 결과]
Map(2) {"spring" => "boot", "node" => "js"}
object
⇒ 초기값으로 이터러블 오브젝트를 작성해주며 대괄호 두개를 통해 2차원 배열로 작성해줬습니다.
Map 오브젝트는 Same-Value-Zero 비교 알고리즘을 따르기 때문에 key값을 비교하여 key 값이 같을경우 value가 대체됩니다. 여기서 key 값을 비교할때는 타입까지 비교하기 때문에 키 값이 100과 "100"이라면 다르다고 판단합니다.
const obj = new Map([
[100, "숫자 100"],
["100", "문자 100"],
[100, "숫자 100 대체"],
]);
for(let [key, value] of obj){
console.log(`${key} : ${value}`);
};
JavaScript
복사
[실행 결과]
100 : 숫자 100 대체
100 : 문자 100
1.
["100", "문자 100"]
⇒ Map 내부에서 "100"이라는 key값을 찾지만 기존에 등록된 100은 타입이 다르기때문에 없는걸로 판단해서 다른 key값으로 등록됩니다.
2.
[100, "숫자 100 대체"]
⇒ Map 내부에서 100이라는 key값을 찾고 [100, "숫자 100"] 를 찾습니다. key의 값과 타입이 같기에 같은 key로 판단해 value를 대체합니다.
Same-Value-Zero비교 알고리즘
2. Map과 Object 비교
지금까지는 주로 Object를 이용해 key/value pair로 사용을 했습니다. 기존 Object를 사용해도 내부에 등록된 프로퍼티 이름으로 값을 꺼내 사용할 수 있는데 Map을 사용하려면 Map의 오브젝트 구조와 차이점을 알 필요가 있습니다.
Map 오브젝트 구조
1.
Map 오브젝트에는 get Symbol(Symbol.species)가 있습니다. 따라서, constructor를 오버라이드 할 수 있습니다.
2.
prototype을 펼치면 Symbol.iterator가 있습니다. 즉, 이터레이터 오브젝트를 반환받아 반복할수 있습니다.
그리고, Map은 배열과 구조가 유사한데 이 역시 Scope를 전개해서 알아봅시다.
const list = [1, 2];
const obj = new Map([
["one", "첫 번째"],
["two", "두 번째"]
]);
debugger
JavaScript
복사
Map 인스턴스인 obj를 전개하면 [[Entries]]가 있습니다. 대괄호 두 개는 엔진에서 설정하는것을 의미합니다. 이를 펼치면 0: {"key" ⇒ "value"} 형태로 나열되있는데 이는 배열구조와 유사합니다. Map또한 인덱스를 부여하여 저장하기에 배열처럼 이터레이션이 가능합니다. 배열과 맵 둘 다 요소 작성 순서대로 인덱스를 부여하여 해당 인덱스의 value로 입력값을 저장하는데 list는 value만 있는반면 map은 형태(key⇒value)로 저장된다는 점이 차이점입니다.
비교
1.
key
•
Map: 타입 제약 없음
•
Object: String, Symbol
2.
{key:value} 수
•
Map: size 프로퍼티로 구함.
•
Object: 전체를 읽어서 구해야 합니다.
3.
처리 시간: MDN
a.
key, value의 추가 삭제가 빈번할수록 Map이 더 뛰어난 성능을 보여줍니다.
3. 값 설정, 추출 메소드:set(), get(), has()
previous
Map 오브젝트에서 제공하는 set, get, has 메소드들은 MDN에도 이미 설명이 잘 나와있고 사용하는데 있어 어려운 함수가 아니기에 간단한 설명과 예제만 작성합니다.
set()
Map 인스턴스에 초기 생성자 파라미터로 이터러블 오브젝트를 작성할 수 있는데, 인스턴스 생성시점에서 파라미터가 아직 없다면 나중에라도 추가할 수 있어야하고 set()메소드를 통해 key/value를 넣어줄 수 있습니다. 그리고 동일하게 Same-Value-Zero 비교 알고리즘을 사용하기에 key값이 같으면 value가 대체됩니다.
let obj = new Map();
obj.set("one", 100);
obj.set({}, "오브젝트");
obj.set(function(){}, "Function");
obj.set(new Number("100"), "인스턴스");
obj.set(NaN, "Not a Number");
for(let [key, value] of obj){
console.log(`${key}: ${value}`);
};
JavaScript
복사
[실행 결과]
one: 100
[object Object]: 오브젝트
function(){}: Function
100: 인스턴스
NaN: Not a Number
get()
파라미터로 작성한 key 값이 map인스턴스 안에 있는지 검사후 있다면 해당 key의 pair인 value를 반환합니다. 만일 key 값이 같지 않거나 타입이 다를 경우 undefined를 반환합니다.
let obj = new Map([
["one", 100],
["200", "String 타입"]
]);
console.log(obj.get("one"));
console.log(obj.get("two"));
console.log(obj.get(200));
JavaScript
복사
[실행 결과]
100
undefined
undefined
has()
Map인스턴스에서 key의 존재 여부를 반환하는 메소드로 key가 있으면 true, 없으면 false반환
const obj = new Map([
["one", 100]
]);
console.log(obj.has("one"));
console.log(obj.has("two"));
JavaScript
복사
[실행 결과]
true
false
4. Map과 이터레이터 오브젝트: entries(), keys(), values(), Symbol.iterator()
previous
Map 오브젝트에서 제공하는 set, get, has 메소드들은 MDN에도 이미 설명이 잘 나와있고 사용하는데 있어 어려운 함수가 아니기에 간단한 설명과 예제만 작성합니다.
entries()
•
Map 인스턴스로 이터레이터 오브젝트를 생성및 반환하는 메소드
•
Map인스턴스에 설정된 순서로 반환
•
next()로 [key, value] 반환
const obj = new Map([
["one", 100],
["two", 200]
]);
const iter = obj.entries();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
JavaScript
복사
[실행 결과]
{value: [one, 100], done: false}
{value: [two, 200], done: false}
{value: undefined, done: true}
keys()
•
Map인스턴스의 key로 이터레이터 오브젝트를 생성, 반환
•
value는 포함하지않으며 Map인스턴스에 설정된 순서로 반환합니다.
•
next()로 key 반환
const obj = new Map([
["one", 100],
["two", 200]
]);
const iter = obj.keys();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
JavaScript
복사
[실행 결과]
{value: "one", done: false}
{value: "two", done: false}
{value: undefined, done: true}
values()
•
Map인스턴스의 value로 이터레이터 오브젝트를 생성및 반환합니다.
•
key는 포함하지 않으며 Map인스턴스에 설정된 순서로 반환합니다.
•
next()로 value 반환
const obj = new Map([
["one", 100],
["two", 200]
]);
const iter = obj.values();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
JavaScript
복사
[실행 결과]
{value: 100, done: false}
{value: 200, done: false}
{value: undefined, done: true}
Symbol.iterator()
•
Map인스턴스로 이터레이터 오브젝트를 생성, 반환
•
Map.prototype.entries()와 동일합니다.
•
next()로 [key, value] 반환
const obj = new Map([
["one", 100],
["two", 200]
]);
const iter = obj[Symbol.iterator]();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
JavaScript
복사
[실행 결과]
{value: [one, 100], done: false}
{value: [two, 200], done: false}
{value: undefined, done: true}
5. 콜백 함수, 삭제, 지우기: forEach(), delete, clear()
forEach()
•
Map 인스턴스를 반복하면서 callback 함수를 호출합니다.
◦
map(), filter()등의 callback함수가 동반되는 메소드는 사용이 불가능합니다.
•
callback 함수에 넘겨주는 파라미터
◦
value, key, Map 인스턴스 key, value순서가 아님
◦
callback 함수에서 this사용
const obj = new Map([
["one", 100],
["two", 200]
]);
const callback = function(value, key, map){
console.log(`${key}, ${value}, ${this.check}`);
};
obj.forEach(callback, {check: 50});
JavaScript
복사
[실행 결과]
one, 100, 50
two, 200, 50
1.
const callback = function(value, key, map){...}
⇒ 콜백함수를 일반 함수로 작성했는데 그 이유는 forEach()에서 두 번째 파라미터로 작성한 Object를 this로 바인딩시키기 위해서는 일반함수를 써야합니다. 만일 arrow function을 사용한다면 this는 window 오브젝트를 참조합니다.
delete()
•
Map 인스턴스에서 파라미터 값과 같은 entry 삭제
•
같은 key가 있으면 true반환하며 없으면 false를 반환
const obj = new Map([
["one", 100],
["two", 200],
[{}, "오브젝트"]
]);
console.log(obj.delete("one"));
console.log(obj.delete({}));
console.log(obj.delete("three"));
console.log(obj);
JavaScript
복사
[실행 결과]
true
false
false
Map(1) {"two" => 200}
1.
obj.delete("one")
⇒ obj 인스턴스 내부의 one 이라는 key를 찾아서 삭제한 뒤 true를 반환합니다.
2.
obj.delete({})
⇒ 얼핏 보면 둘 다 빈 오브젝트이니 가능할 것 같지만 두 오브젝트는 다른 메모리주소를 가지고 있기 때문에 다른 오브젝트이고 obj인스턴스내에서 key를 찾을 수 없기에 false입니다.
3.
obj.delete("three")
⇒ obj 인스턴스 내부의 three라는 key를 찾지만 찾을 수 없기에 false를 반환합니다.
clear()
•
Map인스턴스의 모든 entry를 지웁니다.
•
Map인스턴스 자체를 삭제하는것은 아니며 내부의 entry만 지웁니다.
•
따라서 [key, value]를 다시 추가할 수 있습니다.
•
내부 entry의 수를 알고싶다면 size 프로퍼티를 사용하면 됩니다.
◦
length 프로퍼티와 다르게 size는 개발자가 수정할 수 없습니다.
const obj = new Map([
["one", 100],
["two", 200]
]);
console.log(obj.size);
obj.clear();
console.log(obj.size, ",", obj);
obj.set("add", "추가");
console.log(obj.size);
JavaScript
복사
[실행 결과]
2
0 "," Map(0) {}
1