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, keysvalues생성 방법과 구현 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.