2016-03-09 8 views
12

podstawie mojego zrozumienia docs (here i here) należałoby odwołanie do adresu pamięci do jego pracy:Jak podkładki ES6 Mapa pracować

const foo = {}; 
const map = new Map(); 
map.set(foo,'123'); // Can only be done if memory address of `foo` is known. Any other shimming would require stringification of foo 

To dlatego obiekt JavaScript {} klucze mogą być tylko ciągami (przynajmniej w ES5).

Mimo to widzę Map shim dostępne: https://github.com/zloirock/core-js#map. Próbowałem czytać źródła, ale jego zbyt zgrabnie wydobywane (internally wykorzystuje strong collection which then imports 10 more files)

Pytanie

odpowiedzieć na każde z poniższych proszę

  • Czy istnieje prosty trik do niego i może naprawdę nawet być zrobione (bez uszeregowania)?
  • Być może mutuje foo, aby zapisać na nim jakiś ciąg, a następnie używa go jako klucza?
  • Coś jeszcze i może czytam dokumentację źle?
+4

Jestem prawie pewna, że ​​podkładki używają '===' do porównywania tożsamości obiektu, i dlatego mają wiele operacji O (N) zamiast operacji O (1) lub O (log (N)), które natywne implementacje mogły mieć. –

+0

ES2015 "Mapa" nie może być prawidłowo nałożona, uważam, że najbliższą impaktacją byłoby przechowywanie zapisów kluczy, pewnego rodzaju iteracji i regularnego porównywania z obiektami, jak również wspomina Jeremy. – adeneo

+0

[Tutaj jest] (https://cloud.github.com/downloads/eriwen/es6-map-shim/es6-map-shim-0.2.js) czytelne polyfill btw – adeneo

Odpowiedz

7

Istnieją dwa sposoby, które przychodzą do głowy. Po pierwsze, oczywiście, można mieć tablicę kluczy, i szukać go liniowo:

Map1 = { 
 
    keys: [], 
 
    values: [], 
 
}; 
 

 
Map1.set = function(key, val) { 
 
    var k = this.keys.indexOf(key); 
 
    if(k < 0) 
 
     this.keys[k = this.keys.length] = key; 
 
    this.values[k] = val; 
 
}; 
 

 
Map1.get = function(key) { 
 
    return this.values[this.keys.indexOf(key)]; 
 
}; 
 

 

 
foo = {}; 
 
bar = {}; 
 

 
Map1.set(foo, 'xxx'); 
 
Map1.set(bar, 'yyy'); 
 

 
document.write(Map1.get(foo) + Map1.get(bar) + "<br>")

Drugą opcją jest dodanie specjalnego „klucza” marker do obiektu, który jest używany jako klucz:

Map2 = { 
 
    uid: 0, 
 
    values: {} 
 
}; 
 

 
Map2.set = function(key, val) { 
 
    key = typeof key === 'object' 
 
     ? (key.__uid = key.__uid || ++this.uid) 
 
     : String(key); 
 
    this.values[key] = val; 
 
}; 
 

 
Map2.get = function(key) { 
 
    key = typeof key === 'object' 
 
     ? key.__uid 
 
     : String(key); 
 
    return this.values[key]; 
 
}; 
 

 

 
foo = {}; 
 
bar = {}; 
 

 
Map2.set(foo, 'xxx'); 
 
Map2.set(bar, 'yyy'); 
 

 
document.write(Map2.get(foo) + Map2.get(bar) + "<br>")

przeciwieństwie do 1 opcji, drugi jest O (1). Można to zrobić dokładniej, czyniąc uid nie zapisywalnym/wyliczalnym. Ponadto każde z nich powinno mieć własną nazwę "uid" (można to łatwo ustawić w konstruktorze Map).

7

Trick jest przechowywanie w tablicy i wykonać wyszukiwanie w O (n) przez iterację i za pomocą ścisłego porównania, zamiast stosowania prawdziwej funkcji mieszającej, która byłaby O (1) odnośnika. Na przykład rozważ to:

var myObj = {}; 

var someArray = [{}, {}, myObj, {}]; 

console.log(someArray.indexOf(myObj)); // returns 2 

Oto moja realizacja innej odpowiedzi: Javascript HashTable use Object key

function Map() { 
    var keys = [], values = []; 

    return { 
     put: function (key, value) { 
      var index = keys.indexOf(key); 
      if(index == -1) { 
       keys.push(key); 
       values.push(value); 
      } 
      else { 
       values[index] = value; 
      } 
     }, 
     get: function (key) { 
      return values[keys.indexOf(key)]; 
     } 
    }; 
}