맵과 셋

Grace·2022년 6월 3일
0

JavaScript

목록 보기
3/11
post-thumbnail

맵은 키과 값을 연결한다는 점에서 객체와 비슷하고, 셋은 중복을 허용하지 않는다는 점만 제외하면 배열과 비슷합니다.

Map 객체는 키와 값을 연결할 목적이라면 객체보다 더 좋습니다.
사용자 객체가 여럿 있고 이들에게 각각 역할을 부여한다고 하면

const u1 = {name: 'Cynthia'}
const u2 = {name: 'Jackson'}
const u3 = {name: 'Olive'}
const u4 = {name: 'James'}

먼저 맵을 만듭니다.

const userRoles = new Map()

다음에는 맵의 set() 메서드를 써서 사용자 역할을 할당합니다.

userRoles.set(u1, 'User')
userRoles.set(u2, 'User')
userRoles.set(u3, 'Admin')

set()메서드는 체인으로 연결할 수 있어서 타이핑하는 수고를 덜어줍니다.

userRoles.set(u1, 'User').set(u2, 'User').set(u3, 'Admin')

생성자에 배열의 배열을 넘기는 형대로 써도 됩니다.

const userRoles = new Map([
  	[u1, 'User'],
  	[u2, 'User'],
  	[u3, 'Admin']
  ])

이제 u2의 역할을 알아볼 때는 get() 메서드를 쓰면 됩니다.

userRoles.get(u2) // 'User'

맵에 존재하지 않는 키에 get을 호출하면 undefined를 반환합니다. 맵에 키가 존재하는지 확인하는 has() 메서드도있습니다.

userRoles.has(u1) // true
userRoles.get(u1) // 'User'
userRoles.has(u4) // false
userRoles.get(u4) // undefined

맵에 이미 존재하는 키에 set()을 호출하면 값이 교체됩니다.

userRoles.get(u1) // 'User'
userRoles.set(u1, 'Admin')
userRoles.get(u1) // 'Admin'

size 프로퍼티는 맵의 요소 숫자를 반환합니다.

userRoles.size // 3

keys() 메서드는 맵의 키를, values() 메서드는 값을, entries() 메서드는 첫 번째 요소가 키이고 두 번째 요소가 값인 배열을 각각 반환합니다. 이들 메서드가 반환하는 것은 모두 이터러블 객체이므로 for...of 루프를 쓸 수 있습니다.

for(let u of userRoles.keys()) console.log(u.name)

for(let r of userRoles.values()) console.log(r)

for(let ur of userRoles.entries()) console.log(`${ur[0].name}: ${ur[1]}`)

// 맵도 분해할 수 있습니다.
// 분해하면 좀 더 자연스러운 코드가 됩니다.
for(let [u, r] of userRoles.entries()) console.log(`${ur[0].name}: ${ur[1]}`)

// entries() 메서드는 맵의 기본 이터레이터입니다.
// 위 코드는 다음과 같이 단축해서 쓸 수 있습니다.
for(let [u, r] of userRoles) console.log(`${u.name}: ${r}`)

위크맵

WeakMap은 다음 차이점을 제외하면 Map과 완전히 같습니다.

  • 키는 반드시 객체여야 합니다.
  • WeakMap의 키는 가비지 콜렉션에 포함될 수 있습니다.
  • WeakMap은 이터러블이 아니며 claer() 메서드도 없습니다.

일반적으로 자바스크립트는 코드 어딘가에서 객체를 잠조하는 한 그 객체를 메모리에 계속 유지합니다. 예를 들어 Map의 키인 객체 o가 있다면, 자바스크립트는 Map이 존재하는 한 o를 메모리에 계속 유지합니다. WeakMap에서는 그렇지 않습니다. 따라서 WeakMap은 이터러블이 될 수 없습니다. 가비지 콜렉션 중인 객체를 노출할 위험이 너무 크기 때문입니다.

WeakMap의 이런 특징은 객체 인스턴스의 전용 키를 저장하기에 알맞습니다.

const SecretHolder = (function(){
  const secrets = new WeakMap()
  return class {
    setSecret(secret) {
      secrets.set(this, secret)
    }
    get Secret() {
      return secrets.get(this)
    }
  }
})()

앞의 예제에서는 WeakMap과 그 위크맵을 사용하는 클래스를 함께 IIFE에 넣었습니다. IIFE 외부에서는 그 인스턴스에 비밀스런 내용을 저장할 수 있는 SecretHolder 클래스를 얻게 됩니다. 비밀을 저장할 때는 setScret 메서드를 써야만 하고, 보려 할 때는 getSecret 메서드를 써야만 합니다.

const a = new SecretHolder()
const b = new SecretHolder()

a.setSecret('secret A')
b.setSecret('secret B')

a.getSecret() // 'secret A'
b.getSecret() // 'secret B'

일반적인 Map을 써도 되지만, 그렇게 하면 SecretHolder 인스턴스에 저장한 내용은 가비지 콜렉션에 포함되지 않습니다.

셋은 중복을 허용하지 않는 데이터 집합입니다.
한 사용자에게 여러 역할을 할당하고 싶을 경우에 사용하게 됩니다.

먼저 Set 인스턴스를 만듭니다

const roles = new Set()

이제 사용자 역할을 추가할 때는 add() 메서드를 사용합니다.

roles.add('User') // set['User']

이 사용자에게 관리자 역할을 추가하려면 add()를 다시 호출합니다.

roles.add('Admin') // set['User', 'Admin']

Map과 마찬가지로 Set에도 size 프로퍼티가 있습니다.

roles.size // 2

셋의 장점은 추가하려는 것이 셋에 이미 있는지 확인할 필요가 없습니다. 이미 있다면 아무 일도 일어나지 않습니다.

roles.add('User') // Set['User', 'Admin']
roles.size // 2

역할을 제거할 때는 delete()를 호출합니다. 제거에 성공했다면, 즉 그런 역할이 셋에 존재했다면 true를 반환하고, 그렇지 않다면 false를 반환합니다.

roles.delete('Admin') // true
roles // Set ['User']
roles.delete('Admin') // false

위크셋

위크겟은 객체만 포함할 수 있으며, 이 객체들은 가비지 콜렉션의 대상이 됩니다. WeakMap과 마찬가지로 WeakSet도 이터러블이 아니므로 위크셋의 용도는 매우 적습니다. 위크셋의 실제 용도는 주어진 객체가 셋 안에 존재하는지 아닌지를 알아보는 것뿐이라고 할 수 있습니다.

const naughty = new WeakSet()

const children = [
  {name: 'Suzy'},
  {name: 'Derek'}
 ]

naughty.add(children[1])

for(let child of children) {
  if(naughty.has(child)) {
    console.log(`Coal for ${child.name}!`)
  } else {
    console.log(`Presents for ${child.name}!`)
  }
}
profile
기술블로그 이전:: https://meercat.tistory.com/

0개의 댓글