JS_맵 셋

dev.dave·2023년 7월 25일

Javascript

목록 보기
42/167

//원래는 맵과 셋이 필요도 없었다.
//근데 왜 맵과 셋이 추가가 되었을까요?
//우선,
// 맵, 셋은 객체와 배열을 다루는 건데요...
//오브젝트리터럴(객체) 과 어레이리터럴(배열) 의 차이가 있겠죠? 다른점이요.
//참고로, 자바스크립트는 하나의 기능에 너무 자유도가 높다는게 자바스크립트의 문제점이다.
//그래서,
//일단,
//객체(오브젝트리터럴)는 사람마다 사용하는 방법이 무궁무진하거든요,
//참고로 다른언어에서는 맵으로 제한되있거나, 셋으로 제한되있는 즉, 좀더 전문화된 방법으로 사용한다.
//근데 자바스크립트에서는 객체 쓸떄, 사람들이 너무 자유롭게 사용하다보니까,
//남의 코드를 볼때 너무 헤깔리는거에요, 정형화 되어있지않고 자유롭게 스타일이 너무 다르니까,
//가독성이라든지,,이 객체는 어떤 목적으로 쓴거지?하면서 헤깔리고,,
//그래서 자바스크립트에서도
//결국
// Map, Set 이라는 전문적으로 사용할 객체를 만들었다고 보시면 됩니다.

  // 참고로 Map, Set 에서 속성추가는 set 으로 하고, get은 속성값 조회 , size는 갯수조회 , delete 삭제 이다.
  //그리고 for of / forEach 다 쓸 수 있다.

  //그래서

  //   //객체는 보통,
  //   {'a' : 'b'}
  //   여기서
  //   a가 key이고,
  //   b 는 value(값)이다.
  //즉, key 와 값을 저장하는 객체입니다. (자료구조라고 볼 수도 있죠.)

  //Map을 만들어보자면, 맵 만드는 방법은 여러가지인데,

  const m = new Map(); // 맵이 생성자 이기 때문에, new 를 붙여서 만듭니다.
  //여기서는
  m.set("a", "b"); //이렇게 추가를 하심 되죠. a 는 b 이고,
  m.set("c", "d"); // c 는 d 다.
  // 꺼낼떄는
  m.get("a"); // 이렇게 a를 꺼내면 b가 나오죠.

  const m2 = new Map({ a: "2", b: "3" }); // 뭐 이렇게도 작성할 수 있죠,이 방법은 어떻게 보면 일반 객체를 Map으로 전환하는 방법이라고 볼수도 있겠죠.

  //아무튼

  //   맵이라는 말이 지도잖아요, 배열에서도 맵이 있는걸 아시죠.
  //   맵은 1:1 입니다. 일 대 일 즉, key만이 그안에 내용물을 찾아볼수 있다는 말이죠.
  //    다른 키는 그내용을 볼수없겠죠. 1:1 이니까 1:1로 매칭되는 관계! 그게 맵입니다.
  //   즉, 위에 예제를 보면,
  //   a 는 b와 1:1 관계로 묶여있고,
  //   c 는 d 와 1:1 관계로 묶여있죠,
  //   금고안에 열쇠가 키인데,
  //   a는 a만 열수 있겠죠,
  //   그래서,
  //   키를 열면 안에 내용(value)이 나오죠
  //   즉,
  //   a 는 key이고, 그 안에 내용물(value)은 b 라는 문자열이죠 , 1:1 관계로써,,,말이죠/
  //  맵이 신기한거는,
  //  key를 객체로 둘 수 도있고요,
  //   값(value)도 객체로 둘수가 있겠고, 다양하죠.
  //   m.set(
  //       { a: 'b'}, { c: 'd'}
  //   ); // 이런식으로,,
  // 참고로
  // 이런 객체를 키로 둘경우는,
  // get 할떄(꺼낼떄),
  // m.get({a: 'b'}); 이렇게 하면 안된다.
  // 애초에 객체형태 를 만들어 그 객체를 변수에 저장한 후 꺼내야 된다.
  // 일단 왜 안꺼내지냐면,
  // 참조 값이 달라서 이다.
  // 즉, 예를들어 {a: 'b'} !== { a: 'b'} // true 이다. 왜? 참조값이 달라서 , 즉 다른공간에 저장되기떄문에 다른 애들이다.
  // 그래서
  // 변수에 저장한 후
  // 즉,
  // 객체의 형태를 만든후,
  // const obj = { key: 'value'}
  // m.set(obj, 123); 이렇게 해야
  // m.get(obj) // 123 이렇게 나온다.

  //일반 객체하고는 다르죠.
  //일반 객체는 원래 key는 심볼 아니면 스트링이 줄중 하나만 되는데,
  //맵은 객체도올 수 있고, key : value 를 어떤 형식이든 자유롭게 넣을 수 있어요.

  //그리고
  // 반복 하는 기능인데요,
  //옛날에는 객체에 반복문 돌리기가 너무 힘들었어요,
  //   const obj2 = {};

  //   for (let i in obj2) {
  //     if (obj2.hasOwnProperty(i)) {
  //       // 이거를 써주는 이유는, 객체 프로토타입까지 다나와버리는걸 방지하기위한 보호장치임.
  //       obj2[i];
  //     }
  //   }
  //여튼 예전에는 이렇게 했는데,
  //이런 반복문을 개선을 한게 Map 이다. Map으로 다 처리가능하다.
  //참고로 객체는 length 못쓰는데,
  //Map은 쉽게 길이를 가져올 수 있다.
  //m.size 이런식으로~
  // 여튼 Map은 반복문을 for of 나, forEach 다 돌릴 수 있다.
  const m3 = new Map();
  m3.set("a", "b"); //set(키,값(벨류))으로 Map에 속성 추가.
  m3.set(3, "c"); //문자열이 아닌 값을 키로 사용 가능 합니다.

  const d = {};
  m.set(d, "e"); // 객체도 됩니다.

  m.get(d); //get(키)로 속성값 조회
  console.log(m.get(d)); // e

  m.size; //size로 속성 개수 조회 , length 같은 것임.
  console.log(m.size); // 3

  for (const [k, v] of m) {
    //반복문에 바로 넣어 사용 가능함.
    console.log(k, v); //'a' , 'b', '3', 'c', {}, 'e'
  } // 속성간의 순서도 보장됩니다.

  m.forEach((v, k) => {
    //forEach도 사용가능.
    console.log(k, v); // 결과는 동일
  });

  m.has(d); // has (키) 로 속성 존재 여부를 확인합니다.
  console.log(m.has(d)); // true

  m.delete(d); // delete(키)로 속성 제거.
  m.clear(); //clear()로 전부 제거
  console.log(m.size); // 0

  //Map 은 속성들간의 순서를 보장하고 반복문을 사용할 수 있다. 속성명으로 문자열이 아닌 값을 사용할 수 있고, size메서드를 통해 속성의 수를 쉽게 알수 있다는 점에서 일반 객체와 다르다.

  ///////////////////////////////////////////////////////////////////////

  //Set

  //set은 중복을 허용하지 않는다는 것이 가장 큰 특징입니다. 따라서 배열 자료구조를 사용 하고 싶으나, 중복은 허용하고 싶지 않을때 Set을 사용하면됨.
  //또는 기존 배열에서 중복을 제거하고 싶을떄고 Set을 사용합니다.

  const arr = [1, 3, 2, 7, 2, 6, 3, 5];

  const s = new Set(arr); //{1,3,2,7,6,5} 로 중복제거되어 리턴됨,// 참고로 Set 은 자동 중복 제거
  const result = Array.from(s); // 근데 Set은 객체로 리턴되므로, 배열로 받아보고싶으면 Array.from() 이거 써야함.
  console.log(result); // [1,3,2,7,6,5]

  const s1 = new Set();
  s.add(false); //add(요소)로 Set에 추가합니다
  s.add(1);
  s.add("1");
  s.add(1); //중복이므로 무시
  s.add(2);

  console.log(s.size); // 중복이 제거되어 4

  s.has(1); // has(요소)로 요소 존재 여부를 확인합니다.
  console.log(s.has(1)); // true

  for (const a of s) {
    //요즘은 for in문 안쓰고 for of 문을 많이 쓰죠.
    console.log(a); // false 1 '1' 2
  }

  s.forEach((a) => {
    console.log(a); // false 1 '1' 2
  });

  s.delete(2); // delete(요소)로 요소를 제거합니다
  s.clear(); // clear()로 전부 제거.

  //여튼 Set은 주로 중복 제거할때 많이 쓴다.
  const arr3 = [1, 2, 3, 2, 3, 5, 2];
  const s2 = new Set();
  s2; // 1,2,3,5

  //이런식으로 중복제거되어 잘 나온다.
  // 근데 Set쓰면, 배열로 리턴 안되있고, 객체 자료형으로 리턴되어 나옴.
  // 그래서
  // 배열로 받아보려면,
  Array.from(s2); // [1,2,3,5]
  //이렇게 배열로 받아볼 수 있다.

  /////////////////////////////////////////////////////////////////////

  //보너스로 WeakMap 과 WeakSet 을 알아보면,
  // 이게 Map 과 Set 이긴한데 앞에 Weak 가 붙어있는데, 가비지 컬렉팅이 잘 된다.라는 거다.
  // 키를 객체로 쓸 수 있다고 했는데,,
  const wm = new WeakMap(); //wm 에 위크맵 할당후

  let obj3 = {}; // 빈객체 생성후
  wm.set(obj3, "123"); // wm에 셋해서 빈객체가 키이고, 벨류(값)으로 문자열 123 집어넣음

  obj3 = null; // obj3 가 널로 덮어씌워지면, 빈 객체이므로 가비지 컬렉팅이 되겠죠. 그럼 키의 {}빈객체가 가비지컬렉팅되어 사라지므로,
  // 뒤에 값(value) '123' 도 사라진다.

  let obj4 = {};
  m.set(obj4, "123");
  obj4 = null; // 이렇게 null 줘도 ,
  //그냥 Map은 메모리에 계속 남아있다.

  // 사람들이 null주면 가비지 컬렉팅되는줄 알고, 모르고 쓰는데, 계쏙 메모리에 살아있다.
  //그래서 WeakMap을 쓰는 것이다.
  // 근데 사실 Map 몇백만개 넣는거 아닌 이상은, 메모리 가비지컬렉팅 신경 안써도 된다.

  //WeakMap을 써야하는 때는,
  let user = { name: "zerocho", age: 29 };
  user.married = false; // 속성 추가
  // 근데 이런 방식으로 추가를 하는걸 싫어하는 사람이 있거나,아니면, user 객체를 건들면 안되는 상황이라면,
  // 기존 방식으로는, 새로 객체를 하나 더만들어 거기 추가해서 할당하는 방법은, 보통
  const userObj = {
    user,
    married: false,
  };
  //이런식으로 하는 방법이 있는데, 좀 지저분하게 보일수도, 근데 뭐 틀린건 아니다.
  // 근데,
  //WeakMap 을 사용하면,
  //기존 객체를 수정하지않고, 부가적인 기능을 추가할 수 있다.
  wm.set(user, { married: false }); // 이런식으로

  //그러면,
  user = null; //null 되면
  //나머지 married 이것도 같이 다 사라진다.
  //즉, 하나로 묶여 있고, 같이 날라가는 형태이다. // 키가 날라가면 값도 같이 날라간다.
  // 기존데이터는 건들지 않으면서 , 정보를 저장할 수 있고, 가비지 컬렉팅도 방해하지않으면서 하는 방식이 WeakMap이다.

  //WeakSet은 실전적으로 쓰실일이 있을지 잘 모르겠어요.
profile
🔥개인 메모 / 다른블로그 자료 참조 / 다른블로그 자료 퍼옴 (출처표기) /여기저기서 공부 했던 내용 개인메모 & 참고 / 개인 기록 용도 블로그 입니다.🔥

0개의 댓글