Christoph: Artikel zu und Implementierung von Maps in JavaScript

Moin.

Ich hatte ja bereits angekündigt, eventuell einen Artikel über Maps in JavaScript zu schreiben. Eine erste Vorabversion gibt es bereits.

Bevor es mit dem schreiben weitergeht, wollte ich erstmal die technische Grundlage zur Debatte stellen.

Das ganze basiert auf folgender Hash-Funktion, die meiner Meinung nach sinnvolle Werte liefert (für primitive ihre Darstellung als String, für Objekte eine GUID).

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

Die Map stellt derzeit folgende Funktionalität bereit (ein ? hinter einem Parameternamen kennzeichnet optionale Argumente):

new Map(<linkItems?>) --> <map>
    erzeugt auf Wunsch (und Voreinstellung) eine doppelt-verkettete Liste der Einträge; ohne diese funktioniert alles, was Iteration über die Einträge erforedert, nicht!

Map.from(<obj>, <foreignKeys?>, <linkItems?>) --> <map>
    erzeugt eine Map aus den Eigenschaften eines Objekts; berücksichtigt auf expliziten Wunsch auch ererbte Eigenschaften

<map>.size --> <size>
<map>.isLinked --> <isLinked>
<map>.get(<key>) --> <value>
<map>.put(<key>, <value?>) --> <map>
<map>.remove(<key>) --> <map>
<map>.removeAll() --> <map>
<map>.contains(<key>) --> <containsKey>
<map>.isUndefined(<key>) --> <isUndefined>
    liefert true, falls ein Eintrag existiert und dessen Wert === undefined, sonst false

Folgende Funktionen erlauben Iteration:

<map>.next()
<map>.key() --> <currentKey>
<map>.value() --> <currentValue>

Nutzbar wie folgt:

  
    for(var i = map.size; i--; map.next())  
        doSomethingWith(map.key(), map.value());  

<map>.each(<func>, <thisArg?>) --> <thisArg?>
    übergibt der Funktion drei Argumente: Schlüssel, Wert und ein Flag, ob die Map weitere Elemente enthält

<map>.toString() --> <string>

<map>.flip(<linkItems?>) --> <newMap>
    liefert eine neue Map mit vertauschten Schlüsseln und Werte; da es zu einem Wert mehrere Schlüssel geben kann, sind die Werte der neuen Map Arrays

<map>.drop(<func>, <thisArg?>) --> <map>
    iteriert über die Einträge der Map; die Funktion wird mit aktuellem Schlüssel und Wert als Argument aufgerufen; evaluiert der Rückgabewert der Funktion zu true, wird der aktuelle Eintrag gelöscht

<map>.listValues() --> <value[]>
<map>.listKeys() --> <key[]>

Und hier einige Sonderfunktionen, die ich zur Implementierung eines diff-Algorithmus brauchte:

Map.reverseIndexTableFrom(<array>, <linkItems?>) --> <map>
    ordnet den Array-Einträgen eine Liste mit Indexwerten zu, unter denen sie im Array zu finden sind

Map.cross(<map1>, <map2>, <func>, <thisArg?>) --> <thisArg?>
    führt die Funktion für jeden Map-Eintrag aus, dessen Schlüssel sich sowohl in map1 als auch map2 findet; Argumente der Funktion sind der Schlüssel und die Werte in map1 und map2

Kommentare zur Umsetzung? Was könnte besser gelöst werden, welche Funktionalität fehlt?

Christoph