JS) Map, WeakMap

kangdari·2020년 4월 2일
1

객체의 단점

1. iterable 하지 않다
iterable: 내부 요소들을 하나 하나 순차적으로 반복하여 모든 요소를 검토하는 것

for...in 문은 iterable 하게 보이도록 만들어둔 것이지 실제로 iterable 하지는 않습니다.

const obj = { a: 1, b:2, c:3 }
for (let key in obj){
    console.log(key, obj[key])
}
// a 1
// b 2
// c 3

정확하게 표현할려면 key값이 obj의 property가 맞는지 확인해줘야 합니다.

for(let key in obj){
    if(obj.hasOwnProperty(key)){
        console.log(key, obj[key])
    }
}
  • 객체 -> 배열로 반환
const obj = { a: 1, b: 2, c: 3};

const objToArr = obj => {
    const arr = []
    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            arr.push(key, obj[key])
        }
    }
    return arr;
}

objToArr(obj); // [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ]
const objToArr2 = obj => {
    const arr =[]
    Object.keys(obj).map(key => arr.push([key, obj[key]]))
    return arr
}

objToArr2(obj) // [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ]

2. 키를 문자열로 취급한다.

const obj = {
    1: 10,
    2: 20,
    3: 30
}

let res = 0;
for(let key in obj){
    res += key
}
console.log(res) // 0123
console.log(typeof res) // string

따라서 키값이 unique 함을 완벽하게 보장하지 못함.

const obj = {
    1: 10,
    01: 20,
    '01': 30 // 캐스케이딩 됨.
}
console.log(obj) // { '1': 20, '01': 30 }

3. 프로퍼티의 개수를 직접 파악 불가

const obj = { 1: 10, 2: 20, 3: 30}
console.log(obj.length) // undefined

console.log(Object.keys(obj).length) // 3, 추가 메소드 필요

Map

객체의 장점을 모아 만든 새로운 데이터 타입
1. [key, value] 쌍으로 이루어진 요소들의 집합
2. 순서를 보장하며, iterable 함.
3. 키에는 어떤 데이터타입도 저장할 수 있으며, 문자열로 취급하지 않는다.

const map = new Map()
map.set(1, 10)
map.set(01, 20) // 01 -> 1 숫자로 인식
map.set('1', 30)
map.set([], 40)
map.set({}, 50)
map.set(function(){}, () => {} )
// 1 => 20,
// '1' => 30,
// [] => 40,
// {} => 50,
// [Function (anonymous)] => [Function (anonymous)]

추가 / 가져오기 / 삭제 / 초기화 /요소의 총 개수 /포함 여부 확인

const map = new Map()
map.set('name', 'kang')
map.set('age', 27)

console.log(map.size) // 2
console.log(map.get('name')) // kang

map.delete('age')
console.log(map.has('name')) // true
console.log(map.has('age')) // false

map.clear();
console.log(map.size) // 0

초기 값 지정
인자로 iterable한 개체를 지정할 수 있다.

const arr = [[10, 10], ['10', '10'], [true, false]]

const map = new Map(arr);

map.keys() // MapIterator {10, "10", true}
map.values() //MapIterator {10, "10", false}
map.entries() // MapIterator {10 => 10, "10" => "10", true => false}

배열로 전환
iterator로 반환해줌. next() 사용 가능

const map = new Map([[10, 10], ['10', '10'], [true, false]])
// map은 iterable 하기 때문에 ...연산자 사용이 가능하다.
const mapArr1 = [...map]
const mapArr2 = [...map.keys()]
const mapArr3 = [...map.values()]
const mapArr4 = [...map.entries()]

WeakMap

1. Map과 비교
Map 객체를 키로 하는 데이터를 추가하는 경우 Map에도 해당 객체애 대한 참조가 연결되어, 여타의 참조가 없어지더라도 Map에는 객체가 살아있다.
반면에 WeakMap은 객체에 대한 참조카운터를 올리지 않아(약한 참조), 여타의 참조가 없어질 경우 WeakMap 내의 객체는 GC의 대상이 된다.

let obj1 = { a: 1 } // 참조 카운터 1
const map = new Map() 
// key에만 참조데이터를 넣을 수 있음
map.set(obj1, 10) // 참조 카운터 2
obj1 = null  // 참조 카운터 1

let obj2 = { a: 2 } // 참조 카운터 1
const wmap = new WeakMap()
map.set(obj2, 10) // 참조 카운터 1
obj2 = null // 참조 카운터 0

// wmap은 언젠가 GC 됨

참조형 데이터만 KEY로 설정이 가능

iterable 하지 않음

for...of 사용 불가

size 프로퍼티 없음

keys(), values(), entries(), clear() 사용 불가

비공개 객체 멤버

const weakmapValueAdder = (wmap, key, addValue) => {
    wmap.set(key, Object.assign({}, wmap.get(key), addValue))
}
const Person = (() => {
    const privateMembers = new WeakMap();
    return class {
        constructor(n,a ){
            privateMembers.set(this, { name: n, age: a})
        }
        set name(n) {
            weakmapValueAdder(privateMembers, this, { name : n })
        }
        get name() {
            return privateMembers.get(this).name
        }
        set age(a) {
            weakmapValueAdder(privateMembers, this, { age: a })
        }
        get age() {
            return privateMembers.get(this).age
        }
    }
})()

const kang = new Person('kang', 27)

console.log(kang.name, kang.age, kang) // kang 27 {}

0개의 댓글