„Javascript hash ekvivalentas“

Kaip nurodyta šio atsakymo 3 atnaujinime, šis pavadinimas yra:

 var hash = {}; hash[X] 

faktiškai ne hash objektas X ; jis iš tikrųjų konvertuoja X į eilutę (per .toString() , jei jis yra objektas ar kitos integruotos konversijos skirtingiems primityviems tipams), ir tada atrodo, kad eilutė yra be „ hash “. Objektų identifikavimas taip pat nėra patikrintas - jei du skirtingi objektai turi tą patį eilutės konvertavimą, jie tiesiog perrašo vienas kitą.

Atsižvelgiant į tai - ar yra efektyvių „hashmaps“ diegimų javascript? (Pvz., Antrasis „Google“ javascript hashmap rezultatas „ javascript hashmap suteikia įgyvendinimą, kuris yra O (n) bet kuriai operacijai. Įvairūs kiti rezultatai ignoruoja tai, kad skirtingi objektai su lygiavertėmis eilutėmis atspindi vienas kitą.

237
15 дек. Claudiu yra nustatytas gruodžio 15 d. 2008-12-15 15:56 '08 ne 15:56 2008-12-15 15:56
@ 17 atsakymų

Kodėl gi ne išmaišykite savo objektus ir naudokite gautas eilutes kaip raktinius žodžius įprastam JavaScript žodynui? Galų gale jūs esate geriausioje padėtyje, kad sužinotumėte, kas daro jūsų objektus unikalia. Tai aš darau.

Pavyzdys:

 var key = function(obj){ // some unique object-dependent key return obj.totallyUniqueEmployeeIdKey; // just an example }; var dict = {}; dict[key(obj1)] = obj1; dict[key(obj2)] = obj2; 

Tokiu būdu, galite kontroliuoti indeksavimą, atliktą javascript, be didelių atminties paskirstymo ir perpildymo.

Žinoma, jei tikrai norite „pramoninio sprendimo“, galite sukurti klasifikuojamą klasę pagal pagrindinę funkciją ir visus reikalingus konteinerių API, bet hellip; mes naudojame „JavaScript“ ir stengiamės būti paprasta ir paprasta, todėl šis funkcinis sprendimas yra paprastas ir greitas.

Pagrindinė funkcija gali būti taip paprasta, kaip pasirinkti tinkamus objektų atributus, tokius kaip raktas arba raktų rinkinys, kurie jau yra unikalūs, raktų derinys, kuris yra unikalus kartu arba sudėtingas, pavyzdžiui, naudojant kai kuriuos kriptografinius maišus, kaip DojoX kodavimas arba DojoX UUID . Nors naujausi sprendimai gali sukurti unikalius raktus, aš asmeniškai stengiuosi jų išvengti bet kokia kaina, ypač jei žinau, kas daro savo objektus unikalia.

Atnaujinimas 2014 m .: 2008 m. Šis paprastas sprendimas vis dar reikalauja daugiau paaiškinimų. Leiskite paaiškinti idėją Q A forma.

Jūsų sprendime nėra jokio realaus maišo. Kur tai yra?

„JavaScript“ yra aukšto lygio kalba. Jo pirminiame primityse ( Object ) yra sandėlių lentelė savybėms išsaugoti. Ši maišos lentelė paprastai yra parašyta žemo lygio kalba, siekiant padidinti efektyvumą. Naudojant paprastą objektą su styginių klavišais, mes naudojame efektyviai įgyvendintą maišos lentelę be jokių pastangų.

Kaip jūs žinote, kad jie naudoja maišelį?

Yra trys pagrindiniai būdai, kaip išsaugoti raktų rinkinį:

  • Nereguliuojama. Tokiu atveju, norėdami gauti objektą pagal raktą, privalome eiti per visus raktus, kurie sustoja, kai jį surandame. Vidutiniškai tai atliks n / 2 palyginimus.
  • Užsakyta.
    • # 1 pavyzdys: surūšiuota masyvas - atliekant dvejetainę paiešką, mes pamatysime raktą po lyginimo ~ log2 (n) vidutiniškai. Daug geriau.
    • # 2 pavyzdys: mediena. Vėlgi, jie bus bandymai „log (n)“.
  • Hash lentelė Vidutiniškai tai reikalauja pastovaus laiko. Palyginkite: O (n) ir O (log n) ir O (1). Bumas

Akivaizdu, kad „JavaScript“ objektai vienoje ar kitoje formoje naudoja maišos lenteles, kad tvarkytų įprastas bylas.

Ar naršyklės tikrai naudoja maišos lenteles?

Iš tiesų.

Ar jie atlieka konfliktus?

Taip Žr. Aukščiau. Jei radote susidūrimą su nevienodomis eilutėmis, prašome pranešti apie pardavėjo klaidą.

Taigi, kokia tavo idėja?

Jei norite išjungti objektą, suraskite tai, kas daro jį unikaliu, ir naudokite jį kaip raktą. Nebandykite apskaičiuoti realių maišos ar emuliacijų hash lentelių - tai jau efektyviai tvarko pagrindiniai „JavaScript“ objektai.

Naudokite šį raktą su „JavaScript“ Object kad galėtumėte naudoti įterptą maišos lentelę, vengiant galimų susidūrimų su numatytomis savybėmis.

Pavyzdžiai paleisti:

  • Jei jūsų objektuose yra unikalus naudotojo vardas, naudokite jį kaip raktą.
  • Jei jame yra unikalus kliento numeris, naudokite jį kaip raktą.
    • Jei jame yra unikalūs vyriausybės išduoti numeriai, pvz., SSN arba paso numeris, o jūsų sistema neleidžia dubliavimo, naudokite jį kaip raktą.
  • Jei laukų derinys yra unikalus, naudokite jį kaip raktą.
    • Valstybinė santrumpa + vairuotojo pažymėjimo numeris yra puikus raktas.
    • Šalies santrumpa + paso numeris yra puikus raktas.
  • Kai kuri lauko arba viso objekto funkcija gali grąžinti unikalią vertę - ją naudoti kaip raktą.

Naudodamas naudotojo vardą naudodavau jūsų pasiūlymą ir talpino visus objektus. Bet kai kuris išmintingas vaikinas vadinamas „toString“, kuris yra įmontuotas turtas! Ką turėčiau daryti dabar?

Akivaizdu, kad net jei įmanoma, kad gautas raktas susideda tik iš lotyniškų simbolių, turite kažką daryti. Pvz., Pridėkite bet kokį ne lotynišką Unicode simbolį, kuris jums patinka pradžioje arba pabaigoje, norėdami atrakinti numatytuosius parametrus: "#toString", "#MarySmith". Jei naudojamas sudėtinis raktas, atskiri pagrindiniai komponentai naudoja atskirą ne lotyniškąjį separatorių: "pavadinimas, miestas, valstybė".

Apskritai, tai yra vieta, kur mes turime būti kūrybingi ir pasirinkti paprasčiausius raktus su tam tikrais apribojimais (unikalumas, galimi susidūrimai su numatytomis savybėmis).

Pastaba: unikalūs raktai nesutampa pagal apibrėžimą, o potencialūs maišai susiduria su pagrindiniu Object .

Kodėl jums nepatinka pramoniniai sprendimai?

IMHO, geriausias kodas nėra kodas: jis neturi klaidų, nereikalauja priežiūros, yra lengvai suprantamas ir įvykdomas iš karto. Visos „hash“ lentelės „javascript“ pamačiau> 100 eilutės kodo ir įtraukiau keletą objektų. Palyginkite su: dict[key] = value .

Dar vienas dalykas: ar netgi gali būti viršyta žemo lygio kalba parašyto pirmykščio objekto našumas naudojant „JavaScript“ ir tuos pačius pirmuosius objektus, kad įgyvendintumėte jau įgyvendintą?

Aš vis dar noriu turėti maišos objektus be jokių raktų!

Mums pasisekė: ECMAScript 6 (planuojama paskelbti 2015 m. Viduryje, atiduodama arba užtruks 1-2 metus po to, kai taps plačiai paplitusi) nustatoma pagal žemėlapį ir rinkinį .

Sprendžiant iš apibrėžimo, jie gali naudoti objekto adresą kaip raktą, todėl objektai iš karto skiriasi be dirbtinių raktų. OTOH, du skirtingi, bet identiški objektai bus rodomi kaip atskiri.

247
15 дек. Atsakymą pateikė Eugene Lazutkin . 2008-12-15 17:21 '08 at 17:21 pm 2008-12-15 17:21

Problemos aprašymas

„JavaScript“ neturi integruoto bendrojo žemėlapio tipo (kartais vadinama asociatyvia masyvu ar žodynu), leidžiančią savavališkai pasiekti prieigą prie savavališkų verčių. „JavaScript“ pagrindinė duomenų struktūra yra objektas, specialus žemėlapio tipas, kuris priima tik eilutes kaip raktus ir turi ypatingą semantiką, pvz., Prototipo paveldėjimą, getterius ir steigėjus, ir kitą voodoo.

Kai pasirinktiniai objektai yra žemėlapiai, turite nepamiršti, kad raktas bus konvertuojamas į eilutės reikšmę per „ toString() , kuris 5 ir '5' toString() tą pačią vertę, ir visi objektai, kurie nepakeičia toString() metodo su reikšme indeksuojamas '[object Object]' . Taip pat galite nepageidaujamai pasiekti savo paveldėtas savybes, jei hasOwnProperty() .

Įmontuotas „JavaScript“ masyvo tipas nepadeda vieno bito: „JavaScript“ masyvai nėra asociatyviosios matricos, o tiesiog objektai, turintys keletą papildomų savybių. Jei norite sužinoti, kodėl jie negali būti naudojami kaip žemėlapiai, žr .

Eugeno sprendimas

Jevgenijus Lazutkinas jau apibūdino pagrindinę idėją naudoti pasirinktinį maišos funkciją, kad generuotų unikalias eilutes, kurios gali būti naudojamos ieškant susijusių vertybių kaip žodyno objekto savybės. Tai greičiausiai bus greičiausias sprendimas, nes objektai yra vidiniu būdu įgyvendinami kaip maišos lentelė.

  • Pastaba „Hash“ lentelės (kartais vadinamos maišos kortelėmis) yra konkretus žemėlapio koncepcijos įgyvendinimas, naudojant paramos masyvą ir paiešką pagal skaitines maišos reikšmes. Veikimo laikas gali naudoti kitas struktūras (pvz., Ieškoti medžių ar praleidimo sąrašų), kad būtų galima įdiegti „JavaScript“ objektus, tačiau kadangi objektai yra pagrindinė duomenų struktūra, jie turi būti pakankamai optimizuoti.

Norint gauti unikalią skirtingų reikšmių reikšmę savavališkiems objektams, viena galimybė yra naudoti pasaulinį skaitiklį ir talpyklą iš pačios objekto vertės (pvz., __hash pavadintoje __hash ).

Ši funkcija veikia ir atlieka tiek primityvias vertybes, tiek objektus:

 function hash(value) { return (typeof value) + ' ' + (value instanceof Object ? (value.__hash || (value.__hash = ++arguments.callee.current)) : value.toString()); } hash.current = 0; 

Ši funkcija gali būti naudojama kaip aprašyta Eugene. Kad būtų patogiau, pridėsime ją prie Map klasės.

Mano Map įgyvendinimas

Toliau pateiktas įgyvendinimas papildomai išsaugos raktinių verčių poras dvigubai susietame sąraše, kad būtų užtikrintas greitas kartojimas per raktus ir vertes. Jei norite sukurti savo maišos funkciją, po jos sukūrimo galite perrašyti hash() pavyzdžio metodą.

 // linking the key-value-pairs is optional // if no argument is provided, linkItems === undefined, ie !== false // --> linking will be enabled function Map(linkItems) { this.current = undefined; this.size = 0; if(linkItems === false) this.disableLinking(); } Map.noop = function() { return this; }; Map.illegal = function() { throw new Error("illegal operation for maps without linking"); }; // map initialisation from existing object // doesn't add inherited properties if not explicitly instructed to: // omitting foreignKeys means foreignKeys === undefined, ie == false // --> inherited properties won't be added Map.from = function(obj, foreignKeys) { var map = new Map; for(var prop in obj) { if(foreignKeys || obj.hasOwnProperty(prop)) map.put(prop, obj[prop]); } return map; }; Map.prototype.disableLinking = function() { this.link = Map.noop; this.unlink = Map.noop; this.disableLinking = Map.noop; this.next = Map.illegal; this.key = Map.illegal; this.value = Map.illegal; this.removeAll = Map.illegal; return this; }; // overwrite in Map instance if necessary Map.prototype.hash = function(value) { return (typeof value) + ' ' + (value instanceof Object ? (value.__hash || (value.__hash = ++arguments.callee.current)) : value.toString()); }; Map.prototype.hash.current = 0; // --- mapping functions Map.prototype.get = function(key) { var item = this[this.hash(key)]; return item === undefined ? undefined : item.value; }; Map.prototype.put = function(key, value) { var hash = this.hash(key); if(this[hash] === undefined) { var item = { key : key, value : value }; this[hash] = item; this.link(item); ++this.size; } else this[hash].value = value; return this; }; Map.prototype.remove = function(key) { var hash = this.hash(key); var item = this[hash]; if(item !== undefined) { --this.size; this.unlink(item); delete this[hash]; } return this; }; // only works if linked Map.prototype.removeAll = function() { while(this.size) this.remove(this.key()); return this; }; // --- linked list helper functions Map.prototype.link = function(item) { if(this.size == 0) { item.prev = item; item.next = item; this.current = item; } else { item.prev = this.current.prev; item.prev.next = item; item.next = this.current; this.current.prev = item; } }; Map.prototype.unlink = function(item) { if(this.size == 0) this.current = undefined; else { item.prev.next = item.next; item.next.prev = item.prev; if(item === this.current) this.current = item.next; } }; // --- iterator functions - only work if map is linked Map.prototype.next = function() { this.current = this.current.next; }; Map.prototype.key = function() { return this.current.key; }; Map.prototype.value = function() { return this.current.value; }; 

Pavyzdys

Kitas scenarijus

 var map = new Map; map.put('spam', 'eggs'). put('foo', 'bar'). put('foo', 'baz'). put({}, 'an object'). put({}, 'another object'). put(5, 'five'). put(5, 'five again'). put('5', 'another five'); for(var i = 0; i++ < map.size; map.next()) document.writeln(map.hash(map.key()) + ' : ' + map.value()); 

generuoja šią išvestį:

 string spam : eggs string foo : baz object 1 : an object object 2 : another object number 5 : five again string 5 : another five 

Kiti svarstymai

PEZ pasiūlė perrašyti „ toString() metodą, tikriausiai su mūsų maišos funkcija. Tai neįmanoma, nes ji neveikia primityvių reikšmių atžvilgiu (primityvų keitimas toString() yra labai bloga idėja). Jei norime, kad „ toString() sugrąžintų reikšmingas vertes savavališkiems objektams, mes turėtume pakeisti „ Object.prototype , kurį kai kurie žmonės (neįtraukti į mane) laiko verboten.


Redaguoti: čia galite gauti dabartinę mano Map diegimo versiją ir kitus javascript delikatesus

159
20 дек. Christofo atsakymas, gruodžio 20 d. 2008-12-20 20:57 '08 8:57 pm 2008-12-20 20:57

Žinau, kad šis klausimas yra gana senas, bet šiuo metu yra puikių sprendimų su išorinėmis bibliotekomis.

„JavaScript“ taip pat turi savo kalbos Map .

30
28 сент. Atsakymą pateikė Jamel Toms 28 rugsėjis 2014-09-28 20:50 '14, 20:50, 2014-09-28 20:50

Čia yra paprastas ir patogus būdas naudoti kažką panašaus į „Java“ kortelę:

 var map= { 'map_name_1': map_value_1, 'map_name_2': map_value_2, 'map_name_3': map_value_3, 'map_name_4': map_value_4 } 

Ir norėdami gauti vertę:

 alert( map['map_name_1'] ); // fives the value of map_value_1 ...... etc ..... 
17
10 июля '12 в 14:32 2012-07-10 14:32 atsakymą pateikė Milošas liepos 12 d., 12 val. 14:32 2012-07-10 14:32

Galite naudoti WeakMap arba Map :

  • „WeakMaps“ yra raktų / vertybių žemėlapiai, kuriuose raktai yra objektai.

  • Map objektai yra paprasti raktų / verčių žemėlapiai. Bet kokią vertę (tiek objektus, tiek primityvias reikšmes) galima naudoti kaip raktą arba vertę.

Atminkite, kad nė vienas iš jų nėra plačiai remiamas, bet galite naudoti ES6 Shim (jums reikia savo ES5 arba ES5 Shim ), kad palaikytumėte Map , bet ne „ WeakMap ( žr. Kodėl ).

14
26 дек. atsakymas duotas „ Oriol“ 26 d. 2013-12-26 18:54 '13, 18:54, 2013-12-26 18:54

Jums reikės saugoti kai kurias vidines dvejetaines objekto / vertės porų poras.

 HashMap = function(){ this._dict = []; } HashMap.prototype._get = function(key){ for(var i=0, couplet; couplet = this._dict[i]; i++){ if(couplet[0] === key){ return couplet; } } } HashMap.prototype.put = function(key, value){ var couplet = this._get(key); if(couplet){ couplet[1] = value; }else{ this._dict.push([key, value]); } return this; // for chaining } HashMap.prototype.get = function(key){ var couplet = this._get(key); if(couplet){ return couplet[1]; } } 

Ir naudokite jį kaip:

 var color = {}; // unique object instance var shape = {}; // unique object instance var map = new HashMap(); map.put(color, "blue"); map.put(shape, "round"); console.log("Item is", map.get(color), "and", map.get(shape)); 

Žinoma, šis įgyvendinimas taip pat yra kažkur išilgai O (n) linijų. Pirmiau minėti Eugenijos pavyzdžiai yra vienintelis būdas gauti maišą, kuris veikia bet kokiu greičiu, kurį tikitės iš tikrosios maišos.

Atnaujinti:

Kitas požiūris, pagal Eugeno atsakymą, yra kažkaip pridėti unikalų identifikatorių visiems objektams. Vienas iš mano mėgstamiausių būdų yra vienas iš įmontuotų metodų, paveldėtų iš objekto superklasės, pakeisti jį vartotojo funkcijų profiliu ir pridėti savybių prie šio objekto. Jei norite perrašyti savo „HashMap“ metodą, tai atrodys taip:

 HashMap = function(){ this._dict = {}; } HashMap.prototype._shared = {id: 1}; HashMap.prototype.put = function put(key, value){ if(typeof key == "object"){ if(!key.hasOwnProperty._id){ key.hasOwnProperty = function(key){ return Object.prototype.hasOwnProperty.call(this, key); } key.hasOwnProperty._id = this._shared.id++; } this._dict[key.hasOwnProperty._id] = value; }else{ this._dict[key] = value; } return this; // for chaining } HashMap.prototype.get = function get(key){ if(typeof key == "object"){ return this._dict[key.hasOwnProperty._id]; } return this._dict[key]; } 

Ši versija atrodo šiek tiek greičiau, tačiau teoriškai tai bus daug greičiau dideliems duomenų rinkiniams.

13
15 дек. atsakymas duodamas pottedmeat 15 Dec. 2008-12-15 19:54 '08, 19:54, 2008-12-15 19:54

Deja, nė vienas iš pirmiau pateiktų atsakymų nėra tinkamas mano atvejui: skirtingi pagrindiniai objektai gali turėti tą patį maišos kodą. Todėl parašiau paprastą Java panašią HashMap versiją:

 function HashMap() { this.buckets = {}; } HashMap.prototype.put = function(key, value) { var hashCode = key.hashCode(); var bucket = this.buckets[hashCode]; if (!bucket) { bucket = new Array(); this.buckets[hashCode] = bucket; } for (var i = 0; i < bucket.length; ++i) { if (bucket[i].key.equals(key)) { bucket[i].value = value; return; } } bucket.push({ key: key, value: value }); } HashMap.prototype.get = function(key) { var hashCode = key.hashCode(); var bucket = this.buckets[hashCode]; if (!bucket) { return null; } for (var i = 0; i < bucket.length; ++i) { if (bucket[i].key.equals(key)) { return bucket[i].value; } } } HashMap.prototype.keys = function() { var keys = new Array(); for (var hashKey in this.buckets) { var bucket = this.buckets[hashKey]; for (var i = 0; i < bucket.length; ++i) { keys.push(bucket[i].key); } } return keys; } HashMap.prototype.values = function() { var values = new Array(); for (var hashKey in this.buckets) { var bucket = this.buckets[hashKey]; for (var i = 0; i < bucket.length; ++i) { values.push(bucket[i].value); } } return values; } 

Pastaba: pagrindiniai objektai turi "taikyti" hashCode () ir lygiaverčius () metodus.

10
07 апр. Atsakymas pateikiamas spektom 07 Apr. 2011-04-07 10:25 '11, 10:25, 2011-04-07 10:25

Pagal „ECMAScript 2015“ (ES6) standartą „javascript“ turi žemėlapio įgyvendinimą. Sužinokite daugiau apie tai, ką galima rasti čia.

Pagrindinis naudojimas:

 var myMap = new Map(); var keyString = "a string", keyObj = {}, keyFunc = function () {}; // setting the values myMap.set(keyString, "value associated with 'a string'"); myMap.set(keyObj, "value associated with keyObj"); myMap.set(keyFunc, "value associated with keyFunc"); myMap.size; // 3 // getting the values myMap.get(keyString); // "value associated with 'a string'" myMap.get(keyObj); // "value associated with keyObj" myMap.get(keyFunc); // "value associated with keyFunc" 
9
23 нояб. atsakymą pateikė Riyafa Abdul Hameed lapkričio 23 d 2015-11-23 11:25 '15, 11:25 2015-11-23 11:25

Įdiegiau „JavaScript HashMap“, kurį galima gauti iš http://github.com/lambder/HashMapJS/tree/master

Čia yra kodas:

  var HashMap = function() { this.initialize(); } HashMap.prototype = { hashkey_prefix: "<#HashMapHashkeyPerfix>", hashcode_field: "<#HashMapHashkeyPerfix>", initialize: function() { this.backing_hash = {}; this.code = 0; },  put: function(key, value) { var prev; if (key  value) { var hashCode = key[this.hashcode_field]; if (hashCode) { prev = this.backing_hash[hashCode]; } else { this.code += 1; hashCode = this.hashkey_prefix + this.code; key[this.hashcode_field] = hashCode; } this.backing_hash[hashCode] = value; } return prev; },  get: function(key) { var value; if (key) { var hashCode = key[this.hashcode_field]; if (hashCode) { value = this.backing_hash[hashCode]; } } return value; },  del: function(key) { var success = false; if (key) { var hashCode = key[this.hashcode_field]; if (hashCode) { var prev = this.backing_hash[hashCode]; this.backing_hash[hashCode] = undefined; if(prev !== undefined) success = true; } } return success; } } //// Usage // creation var my_map = new HashMap(); // insertion var a_key = {}; var a_value = {struct: "structA"}; var b_key = {}; var b_value = {struct: "structB"}; var c_key = {}; var c_value = {struct: "structC"}; my_map.put(a_key, a_value); my_map.put(b_key, b_value); var prev_b = my_map.put(b_key, c_value); // retrieval if(my_map.get(a_key) !== a_value){ throw("fail1") } if(my_map.get(b_key) !== c_value){ throw("fail2") } if(prev_b !== b_value){ throw("fail3") } // deletion var a_existed = my_map.del(a_key); var c_existed = my_map.del(c_key); var a2_existed = my_map.del(a_key); if(a_existed !== true){ throw("fail4") } if(c_existed !== false){ throw("fail5") } if(a2_existed !== false){ throw("fail6") } 
5
09 июля '09 в 23:20 2009-07-09 23:20 atsakymą pateikė Lambder liepos 9 d. 09:23 23:20 2009-07-09 23:20

ECMA6 galite naudoti „ WeakMap“

Pavyzdys:

 var wm1 = new WeakMap(), wm2 = new WeakMap(), wm3 = new WeakMap(); var o1 = {}, o2 = function(){}, o3 = window; wm1.set(o1, 37); wm1.set(o2, "azerty"); wm2.set(o1, o2); // a value can be anything, including an object or a function wm2.set(o3, undefined); wm2.set(wm1, wm2); // keys and values can be any objects. Even WeakMaps! wm1.get(o2); // "azerty" wm2.get(o2); // undefined, because there is no value for o2 on wm2 wm2.get(o3); // undefined, because that is the set value wm1.has(o2); // true wm2.has(o2); // false wm2.has(o3); // true (even if the value itself is 'undefined') wm3.set(o1, 37); wm3.get(o1); // 37 wm3.clear(); wm3.get(o1); // undefined, because wm3 was cleared and there is no value for o1 anymore wm1.has(o1); // true wm1.delete(o1); wm1.has(o1); // false 

Bet:

 Because of references being weak, WeakMap keys are not enumerable (ie there is no method giving you a list of the keys). 
3
12 нояб. atsakymas pateiktas Nr . 2013-11-12 10:33 '13, 10:33, 2013-11-12 10:33

Jei našumas nėra kritinis (pvz., Raktų skaičius yra palyginti mažas) ir nenorite užteršti objektų (arba galbūt ne jūsų) papildomais laukais, pvz., _hash , _id ir tt, tada galite naudoti faktą Array.prototype.indexOf naudoja griežtą lygybę. Štai paprastas įgyvendinimas:

 var Dict = (function(){ // IE 8 and earlier has no Array.prototype.indexOf function indexOfPolyfill(val) { for (var i = 0, l = this.length; i < l; ++i) { if (this[i] === val) { return i; } } return -1; } function Dict(){ this.keys = []; this.values = []; if (!this.keys.indexOf) { this.keys.indexOf = indexOfPolyfill; } }; Dict.prototype.has = function(key){ return this.keys.indexOf(key) != -1; }; Dict.prototype.get = function(key, defaultValue){ var index = this.keys.indexOf(key); return index == -1 ? defaultValue : this.values[index]; }; Dict.prototype.set = function(key, value){ var index = this.keys.indexOf(key); if (index == -1) { this.keys.push(key); this.values.push(value); } else { var prevValue = this.values[index]; this.values[index] = value; return prevValue; } }; Dict.prototype.delete = function(key){ var index = this.keys.indexOf(key); if (index != -1) { this.keys.splice(index, 1); return this.values.splice(index, 1)[0]; } }; Dict.prototype.clear = function(){ this.keys.splice(0, this.keys.length); this.values.splice(0, this.values.length); }; return Dict; })(); 

Naudojimo pavyzdys:

 var a = {}, b = {}, c = { toString: function(){ return '1'; } }, d = 1, s = '1', u = undefined, n = null, dict = new Dict(); // keys and values can be anything dict.set(a, 'a'); dict.set(b, 'b'); dict.set(c, 'c'); dict.set(d, 'd'); dict.set(s, 's'); dict.set(u, 'u'); dict.set(n, 'n'); dict.get(a); // 'a' dict.get(b); // 'b' dict.get(s); // 's' dict.get(u); // 'u' dict.get(n); // 'n' // etc. 

Сравнение с ES6 WeakMap имеет две проблемы: O (n) время поиска и не-слабость (т.е. это приведет к утечке памяти, если вы не используете клавиши delete или clear для выпуска ключей).

2
ответ дан skozin 21 нояб. '13 в 2:11 2013-11-21 02:11