돌아가기

'읽음'상태인 메시지 저장하기

중요도: 5

메시지가 저장되어 있는 배열이 있습니다.

let messages = [
  {text: "Hello", from: "John"},
  {text: "How goes?", from: "John"},
  {text: "See you soon", from: "Alice"}
];

여러분이 작성하고 있는 코드를 사용해 이 배열에 접근할 수 있지만, 메시지를 관리하는 건 다른 코드에서 이뤄지고 있는 상황입니다. 새로운 메시지가 있으면 배열에 추가되고, 오래된 메시는 배열에서 삭제되지만 이런 작업은 외부코드에 의해 이뤄지고 있기 때문에 여러분은 언제 메시지가 추가/삭제되는지 알 수 없는 상황이죠.

이와 같은 상황에서 ‘읽음’ 상태의 메시지는 어떤 자료구조에 저장해야 좋을까요? 특정 메시지 객체를 대상으로 "메시지가 읽음 상태인가요?"라는 질문을 던지면 제대로 된 답이 반환되는 자료구조는 무엇일까요?

주의: messages에서 특정 메시지가 삭제되면 여러분이 구현할 자료구조에서도 해당 메시지가 삭제되어야 합니다.

주의: 메시지 객체에 프로퍼티를 추가하는 것과 같이 메시지 객체를 수정해선 안 됩니다. 메시지 객체는 외부코드에서 관리하고 있기 때문에 메시지 객체를 직접 수정하면 예상치 않은 결과가 나타날 수 있습니다.

위크셋에 읽음 상태의 메시지를 저장해봅시다.

let messages = [
  {text: "Hello", from: "John"},
  {text: "How goes?", from: "John"},
  {text: "See you soon", from: "Alice"}
];

let readMessages = new WeakSet();

// 메시지 두 개가 읽음 상태로 변경되었습니다.
readMessages.add(messages[0]);
readMessages.add(messages[1]);
// readMessages엔 요소 두 개가 저장됩니다.

// 첫 번째 메시지를 다시 읽어봅시다!
readMessages.add(messages[0]);
// readMessages에는 요소 두 개가 여전히 저장되어 있습니다(중복 요소 없음).

// "'message[0]'은 읽음 상태인가요?"에 대한 답변
alert("message 0은 읽음 상태인가요?: " + readMessages.has(messages[0])); // true

messages.shift();
// 이제 readMessagesreadMessages에는 요소가 하나만 남게 되었습니다(실제 메모리에서 사라지는 건 나중이 되겠지만 말이죠).

위크셋을 사용하면 메시지를 저장하고 위크셋 내에 메시지가 있는지 여부를 쉽게 확인할 수 있습니다.

위크셋은 자동으로 자신을 청소한다는 장점이 있습니다. 다만 이 장점 때문에 반복 작업이 불가능해서 읽음 상태의 메시지를 ‘한꺼번에’ 가지고 오지 못한다는 단점도 생깁니다. 배열에 저장된 모든 메시지를 대상으로 반복 작업을 수행해 해당 메시지가 위크셋에 저장되어 있는지 확인하면 읽음 상태의 메시지를 ‘한 번에’ 얻어올 수 있습니다.

위크셋을 사용하지 않고 메시지 객체에 message.isRead=true같은 프로퍼티를 추가해도 메시지가 읽음 상태인지 확인할 수 있습니다. 그런데 messages와 메시지 객체는 외부 코드에서 관리하고 있기 때문에 이 방법을 권장하는 편은 아닙니다. 심볼형 프로퍼티를 사용하면 충돌을 피할 수는 있습니다.

예시:

// 우리 코드에서만 심볼형 프로퍼티의 정보를 얻을 수 있습니다.
let isRead = Symbol("isRead");
messages[0][isRead] = true;

이렇게 하면 서드파티 코드에서는 위에서 추가한 여분의 프로퍼티를 볼 수 없습니다.

심볼을 사용하면 문제 발생 확률을 낮출 순 있지만, 위크셋을 쓰는 게 보다 건설적인 접근법입니다.