ES6 Map과 WeakMap의 차이점은 무엇입니까?


94

찾는 이 와 이 이지도와 WeakMaps 사이의 유일한 차이처럼 보인다 MDN 페이지 것은 WeakMaps에 대한 누락 "크기"속성입니다. 그러나 이것이 사실입니까? 그들 사이의 차이점은 무엇입니까?


효과는 GC에 있습니다. WeakMaps는 키를 수집 할 수 있습니다.
— John Dvorak

@JanDvorak MDN에 대해 지적한 예가 없습니다. aWeakMap.get (key); // 말, 2 ... (GC 액션) ... aWeakMap.get (key); 정의되지 않은 // 말하자면,
— Dmitrii 소린

1
당신의 모범은 불가능합니다. key귀하가 참조하기 때문에 수집 할 수 없습니다.
— 존 드보락

1
디자인 결정은 GC 작업이 Javascript에서 보이지 않는다는 것입니다. GC가 그 일을하는 것을 관찰 할 수 없습니다.
— John Dvorak 2013 년

1
참조 이 관련 대답 이 문제에 대한 자세한 내용은.
— Benjamin Gruenbaum

답변:


54

에서 매우 같은 페이지, 섹션 " 왜 약한 지도? " :

숙련 된 JavaScript 프로그래머는이 API가 4 개의 API 메서드가 공유하는 두 개의 배열 (키용 하나, 값용 하나)을 사용하여 JavaScript에서 구현 될 수 있음을 알게 될 것입니다. 이러한 구현에는 두 가지 주요 불편 함이 있습니다. 첫 번째는 O (n) 검색입니다 (n은 맵의 키 수). 두 번째는 메모리 누수 문제입니다. 수동으로 작성된 맵을 사용하면 키 배열이 키 개체에 대한 참조를 유지하여 가비지 수집을 방지합니다. 네이티브 WeakMaps에서 키 객체에 대한 참조는 "약하게" 유지 됩니다. 즉, 객체에 대한 다른 참조가 없을 경우 가비지 수집을 방지하지 않습니다.

참조가 약하기 때문에 WeakMap 키는 열거 할 수 없습니다 (즉, 키 목록을 제공하는 메서드가 없습니다). 그럴 경우 목록은 가비지 수집 상태에 따라 달라지며 비결 정성을 도입합니다.

[그것도 size재산 이없는 이유입니다 ]

키 목록을 갖고 싶다면 직접 유지해야합니다. 약한 참조를 사용하지 않고 열거 할 수있는 간단한 집합과 맵을 도입하는 것을 목표로 하는 ECMAScript 제안 도 있습니다.

-이 될 것이다 "정상" Map의 . MDN에 언급,하지만하지 조화를 제안 , 그 또한 가지고 items, keys및 values생성 방법과 구현 Iterator인터페이스를 .


그래서 new Map().get(x)일반 객체에서 속성을 읽기와 같은 룩업 시간에 대해이있다?
— Alexander Mills

1
@AlexanderMills 이것이 질문과 관련이 있는지 모르겠지만 여기에 몇 가지 데이터가 있습니다. 일반적으로, 예 그들은 비슷 하고, 적절한 하나를 사용한다 .
— Bergi

그래서 내 이해는 Map이 해당 배열로 인해 키를 유지하기 위해 내부 배열을 유지한다는 것입니다. 가비지 수집기는 참조를 자제 할 수 없습니다. WeekMap에는 키가 유지되는 배열이 없으므로 참조가없는 키는 가비지 수집 될 수 있습니다.
— Mohan Ram

@MohanRam A는 WeakMap여전히 항목의 배열 (또는 다른 컬렉션)을 가지고 있으며 가비지 수집기에 약한 참조 임을 알립니다 .
— Bergi

그렇다면 WeekMap 키에 대한 반복이 지원되지 않는 이유는 무엇입니까?
— Mohan Ram

93

키 / 값이 참조하는 객체가 삭제되면 둘 다 다르게 작동합니다. 아래 예제 코드를 살펴 보겠습니다.

var map = new Map();
var weakmap = new WeakMap();

(function(){
    var a = {x: 12};
    var b = {y: 12};

    map.set(a, 1);
    weakmap.set(b, 2);
})()

위의 인생은 우리가 참조 할 수있는 방법은 없습니다 실행 {x: 12}하고 {y: 12}더 이상은. 가비지 수집기는 계속해서 "WeakMap"에서 키 b 포인터를 삭제 {y: 12}하고 메모리 에서도 제거합니다 . 그러나“Map”의 경우 가비지 수집기는“Map”에서 포인터를 제거하지 않고 {x: 12}메모리 에서도 제거하지 않습니다 .

요약 : WeakMap을 사용하면 가비지 수집기가 작업을 수행 할 수 있지만 Map은 수행 할 수 없습니다.

참조 : http://qnimate.com/difference-between-map-and-weakmap-in-javascript/


13
메모리에서 제거되지 않는 이유는 무엇입니까? 여전히 참조 할 수 있기 때문입니다! map.entries().next().value // [{x:12}, 1]
— Bergi

4
자체 호출 함수가 아닙니다. 즉시 호출되는 함수 표현식입니다. benalman.com/news/2010/11/…
— Olson.dev

다음 weakmap와 객체 사이의 차이점은 무엇입니까
— 무하마드 Umer

@MuhammadUmer : 객체는 문자열 '키' WeakMap만 가질 수 있지만 기본이 아닌 키만 가질 수 있습니다 (문자열 또는 숫자 또는 Symbol키로서의 s, 배열, 객체, 기타 맵 등).
— Ahmed Fasih

1
@nnnnnn 예 그게은 여전히 차이 것입니다 Map 에 있지만WeakMap
— 알렉산더 Derck

75

아마도 다음 설명은 누군가에게 더 분명 할 것입니다.

var k1 = {a: 1};
var k2 = {b: 2};

var map = new Map();
var wm = new WeakMap();

map.set(k1, 'k1');
wm.set(k2, 'k2');

k1 = null;
map.forEach(function (val, key) {
    console.log(key, val); // k1 {a: 1}
});

k2 = null;
wm.get(k2); // undefined

보시다시피 k1메모리에서 키를 제거한 후에도 지도 내에서 계속 액세스 할 수 있습니다. 동시에 k2WeakMap의 키를 제거하면 wm참조로도 제거됩니다 .

이것이 WeakMap이 forEach와 같은 열거 가능한 메서드가없는 이유입니다. WeakMap 키 목록과 같은 것이 없기 때문에 다른 개체에 대한 참조 일뿐입니다.


10
물론 마지막 줄에서 wm.get (null)은 정의되지 않습니다.
— DaNeSh

8
mozilla 사이트, kudos에서 복사하여 붙여 넣는 것보다 더 나은 대답입니다.
— Joel Hernandez

2
에 forEach, (key, val)실제로 일해야한다(val, key)
— 미구엘 모타


34

또 다른 차이점 (출처 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap ) :

WeakMaps의 키는 Object 유형입니다. 키로서의 원시 데이터 유형은 허용되지 않습니다 (예 : Symbol은 WeakMap 키가 될 수 없음).

문자열, 숫자 또는 부울을 WeakMap키로 사용할 수도 없습니다 . A Map 는 키에 기본 값을 사용할 수 있습니다.

w = new WeakMap;
w.set('a', 'b'); // Uncaught TypeError: Invalid value used as weak map key

m = new Map
m.set('a', 'b'); // Works

6
누군가 궁금해 할 경우 :이 이유는 기본 유형에 대한 참조를 유지하거나 전달할 수 없기 때문입니다. 따라서 WeakMap의 키는 유일한 참조입니다. 그렇게하면 가비지 수집이 불가능합니다. 약한 참조가 불가능한지 또는 이해가되지 않는지 모르겠습니다. 그러나 어느 쪽이든 키는 약하게 참조 할 수있는 것이어야합니다.
— Andreas Linnert

3

에서 Javascript.info

지도 -일반지도에서 객체를 키로 사용하면지도가 존재하는 동안 해당 객체도 존재합니다. 메모리를 차지하고 가비지 수집되지 않을 수 있습니다.

let john = { name: "John" };
let array = [ john ];
john = null; // overwrite the reference

// john is stored inside the array, so it won't be garbage-collected
// we can get it as array[0]

마찬가지로 일반지도에서 객체를 키로 사용하면지도가있는 동안 해당 객체도 존재합니다. 메모리를 차지하며 가비지 수집되지 않을 수 있습니다.

let john = { name: "John" };
let map = new Map();
map.set(john, "...");
john = null; // overwrite the reference

// john is stored inside the map,
// we can get it by using map.keys()

WeakMap- 이제 객체를 키로 사용하고 해당 객체에 대한 다른 참조가 없으면 메모리 (및 맵)에서 자동으로 제거됩니다.

let john = { name: "John" };
let weakMap = new WeakMap();
weakMap.set(john, "...");
john = null; // overwrite the reference

// john is removed from memory!

3

자바 스크립트의 WeapMap은 키 또는 값을 보유하지 않으며 고유 ID를 사용하여 키 값을 조작합니다. 하고 키 개체에 속성을 정의합니다.

이에 속성을 정의하기 때문에 key object방법으로 Object.definePropert(), 키 원시 형이 아니어야합니다 .

또한 WeapMap에는 실제로 키 값 쌍이 포함되어 있지 않기 때문에 weakmap의 길이 속성을 얻을 수 없습니다.

또한 조작 된 값은 키 객체에 다시 할당되며, 가비지 수집기는 사용하지 않는 경우 쉽게 키를 수집 할 수 있습니다.

구현을위한 샘플 코드.

if(typeof WeapMap != undefined){
return;
} 
(function(){
   var WeapMap = function(){
      this.__id = '__weakmap__';
   }
        
   weakmap.set = function(key,value){
       var pVal = key[this.__id];
        if(pVal && pVal[0] == key){
           pVal[1]=value;
       }else{
          Object.defineProperty(key, this.__id, {value:[key,value]});
          return this;
        }
   }

window.WeakMap = WeakMap;
})();

구현 참조


1
명확히 말하면이 구현은 절반 만 작동합니다. 여러 약한 맵에서 키와 동일한 개체를 사용하는 것은 허용되지 않습니다. 또한 고정 된 개체에 대해서는 작동하지 않습니다. 그리고 물론 객체에 대한 참조를 가진 사람에게 매핑을 유출합니다. 첫 번째는 기호를 사용하여 수정할 수 있지만 후자의 두 가지는 수정할 수 없습니다.
— Andreas Rossberg

@AndreasRossberg이 구현에서는 hardcoded를 추가 id했지만 Math.random 및 Date.now () 등을 사용하여 고유해야합니다. 그리고이 동적 ID를 추가하면 첫 번째 요점이 해결 될 수 있습니다. 마지막 두 가지 요점에 대한 해결책을 알려주시겠습니까?
— Ravi Sevta

첫 번째 문제는 기호를 사용하여보다 우아하게 해결됩니다. 후자의 두 가지는 JS 내에서 해결 될 수 없기 때문에 WeakMap은 언어에서 원시적이어야합니다.
— Andreas Rossberg

1

WeakMap 키는 원시 값이 아닌 객체 여야합니다.

let weakMap = new WeakMap();

let obj = {};

weakMap.set(obj, "ok"); // works fine (object key)

// can't use a string as the key
weakMap.set("test", "Not ok"); // Error, because "test" is not an object

왜????

아래 예를 보겠습니다.

let user = { name: "User" };

let map = new Map();
map.set(user, "...");

user = null; // overwrite the reference

// 'user' is stored inside the map,
// We can get it by using map.keys()

객체를 일반에서 키로 사용하면 존재 Map하는 동안 Map해당 객체도 존재합니다. 메모리를 차지하고 가비지 수집되지 않을 수 있습니다.

WeakMap이 측면에서 근본적으로 다릅니다. 키 개체의 가비지 수집을 방지하지 않습니다.

let user = { name: "User" };

let weakMap = new WeakMap();
weakMap.set(user, "...");

user = null; // overwrite the reference

// 'user' is removed from memory!

객체를 키로 사용하고 해당 객체에 대한 다른 참조가없는 경우 메모리 (및 맵)에서 자동으로 제거됩니다.

WeakMap 반복 및 메서드 키 () , 값 () , 항목 ()을 지원 하지 않습니다. 모든 키 또는 값을 가져올 방법이 없습니다.

WeakMap에는 다음 메서드 만 있습니다.

  • weakMap.get (키)
  • weakMap.set (키, 값)
  • weakMap.delete (키)
  • weakMap.has (키)

객체가 다른 모든 참조 (위 코드의 'user'와 같은)를 잃어버린 경우 자동으로 가비지 수집됩니다. 그러나 기술적으로는 정리가 발생하는시기가 정확히 지정되어 있지 않습니다.

JavaScript 엔진이이를 결정합니다. 메모리 정리를 즉시 수행하거나 더 많은 삭제가 발생할 때 기다렸다가 나중에 정리하도록 선택할 수 있습니다. 따라서 기술적으로 a의 현재 요소 개수 WeakMap는 알 수 없습니다. 엔진이 청소했거나 청소하지 않았거나 부분적으로 수행했을 수 있습니다. 따라서 모든 키 / 값에 액세스하는 메서드는 지원되지 않습니다.

참고 : -WeakMap의 주요 적용 영역은 추가 데이터 저장소입니다. 객체가 가비지 수집 될 때까지 객체를 캐싱하는 것과 같습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.