(pseudo-)assoziative arrays in javascript: naming collisions mit methoden
![](/uploads/users/avatars/000/000/155/thumb/missing.png)
- array
- javascript
0 Matthias Apsel
2 dedlfix
0 seth
0 dedlfix
0 1unitedpower
0 kai345
0 seth
gudn tach!
nach vielen jahren muss ich mich mal wieder mit js beschaeftigen und fuehle mich soo doof.
assoziative arrays sind in js wohl objekte (oder umgekehrt, je nach sichtweise). das kann, wenn man hashes/maps von anderen sprachen wie perl oder c++ kennt, zu unerwarteten ergebnissen fuehren.
der code-schnipsel
var some_object = {};
some_object['init'] = true;
if(some_object['constructor']){
destroy_earth();
}
wuerde (wenn die funktion destroy_earth
korrekt implementiert ist), fatale folgen haben.
denn some_object
besitzt als objekt standardmaessig die methode constructor
(sowie weitere methoden wie toString
etc.)
im konkreten fall koennte ich durch explizites abfragen den code wohl retten:
var some_object = {};
some_object['init'] = true;
if(some_object['constructor'] === true){
destroy_earth(); // wird nun nicht mehr aufgerufen
}
oder ich mach's noch expliziter:
var some_object = {};
some_object['init'] = true;
const key = 'constructor';
if(Object.keys(some_object).includes(key)
&& some_object[key] === true){
destroy_earth();
}
aber so richtig sauber sieht mir das noch nicht aus -- geschweige denn elegant.
was waere denn in modernem javascript (und ohne jquery oder andere libs) ein sauberer weg, hashes/maps nutzen zu koennen, sodass ich mir keine gedanken darueber zu machen brauche, ob evtl. bereits eine methode existiert, die den gleichen namen traegt wie ein key eines key-value-pairs?
prost
seth
Hallo seth,
gudn tach!
Schön, mal wieder von dir zu lesen. Ich hoffe, du bekommst es hin, die Erde nicht zu zerstören 😀.
Bis demnächst
Matthias
gudn tach!
Schön, mal wieder von dir zu lesen. Ich hoffe, du bekommst es hin, die Erde nicht zu zerstören 😀.
schoen, mal wieder hier zu sein und bekannte namen zu lesen. 25 jahre, krasser scheiss. 😀
die erde wird bereits von den anderen zerstoert. da brauche ich gar nix mehr zu machen.
prost
seth
Hallo,
die erde wird bereits von den anderen zerstoert. da brauche ich gar nix mehr zu machen.
du sprichst von den Vogonen?
Gruß
Kalk
Tach!
assoziative arrays sind in js wohl objekte (oder umgekehrt, je nach sichtweise).
Es sind Objekte. Auch Arrays sind Objekte. Sagt zumindest der typeof. Es andersrum zu betrachten ist theoretisch möglich, aber praktisch nicht weiter sinnvoll.
denn
some_object
besitzt als objekt standardmaessig die methodeconstructor
(sowie weitere methoden wietoString
etc.)
Genauer gesagt, der Prototyp besitzt diese Methoden. Das ist von Vorteil, denn some_object.hasOwnProperty()
liefert in dem Fall false.
oder ich mach's noch expliziter: […]
Object.keys(some_object)
[…]
Auch so, aber eher, wenn man darüber iterieren möchte.
was waere denn in modernem javascript (und ohne jquery oder andere libs) ein sauberer weg, hashes/maps nutzen zu koennen, sodass ich mir keine gedanken darueber zu machen brauche, ob evtl. bereits eine methode existiert, die den gleichen namen traegt wie ein key eines key-value-pairs?
Object.keys()
beim Iterieren, .hasOwnProperty()
bei einzelner Abfrage.
Übrigens, in modernem Javascript braucht man auch kein var
mehr. In deinen Beispielen kannst du auch für some_object
const
verwenden.
dedlfix.
gudn tach!
assoziative arrays sind in js wohl objekte (oder umgekehrt, je nach sichtweise).
Es sind Objekte. Auch Arrays sind Objekte. Sagt zumindest der typeof. Es andersrum zu betrachten ist theoretisch möglich, aber praktisch nicht weiter sinnvoll.
ok. gelegentlich bin ich ueber solche aussagen gestolpert:
"I explain how JavaScript objects are also associative arrays (hashes)." (quelle: Objects as associative arrays, quirksmode.org)
some_object.hasOwnProperty()
liefert in dem Fall false.
ok, das heisst, ich muss, wenn ich hashes nutze, tatsaechlich diese zusaetzliche bedingung einbauen?
const some_object = {};
some_object['init'] = true;
const key = 'constructor';
if(some_object.hasOwnProperty(key) && some_object[key] === true){
destroy_earth();
}
finde ich immer noch nicht huebsch, sondern fehleranfaellig.
ich habe bei meiner weiteren recherche soeben noch Map gefunden. vielleicht ist das besser geeignet. damit waere der obige code wohl:
const some_object = new Map();
some_object.set('init', true);
const key = 'constructor';
if(some_object.get(key)){
destroy_earth();
}
das sieht sauberer aus.
Übrigens, in modernem Javascript braucht man auch kein
var
mehr.
ach so, stimmt ja. das heisst jetzt let
(und verhaelt sich dann endlich so, wie man's von anderen sprachen bereits kennt), hatte ich sogar gelesen, aber wieder vergessen, danke fuer die erinnerung.
In deinen Beispielen kannst du auch für
some_object
const
verwenden.
ah, das const, bezieht sich nur auf die oberste ebene des objekts und nicht auf die properties, ok. finde ich nicht intuitiv, aber gut zu wissen. hab's jetzt nachgelesen.
prost
seth
Tach!
some_object.hasOwnProperty()
liefert in dem Fall false.ok, das heisst, ich muss, wenn ich hashes nutze, tatsaechlich diese zusaetzliche bedingung einbauen?
const some_object = {}; some_object['init'] = true; const key = 'constructor'; if(some_object.hasOwnProperty(key) && some_object[key] === true){ destroy_earth(); }
finde ich immer noch nicht huebsch, sondern fehleranfaellig.
Es kommt auf die eigentliche Aufgabenstellung an. Das Problem tritt doch nur auf, wenn key
kein bekannter konstanter Wert ist, also aus einer unbekannten Quelle kommt. In dem Fall ist etwas mehr Aufwand nötig, um ihn für alle Werte sicher einsetzen zu können.
ich habe bei meiner weiteren recherche soeben noch Map gefunden. vielleicht ist das besser geeignet. damit waere der obige code wohl:
const some_object = new Map(); some_object.set('init', true); const key = 'constructor'; if(some_object.get(key)){ destroy_earth(); }
das sieht sauberer aus.
Ja, Map gibt es auch. Wenn man nur einen einfachen Key-Value-Speicher braucht, kann man das nehmen. Objekte haben noch andere Eigenschaften. Das muss man für seinen konkreten Fall klären, was da sinnvoller ist.
In deinen Beispielen kannst du auch für
some_object
const
verwenden.ah, das const, bezieht sich nur auf die oberste ebene des objekts und nicht auf die properties, ok. finde ich nicht intuitiv, aber gut zu wissen.
Muss aber so sein. Man kann nicht garantieren, dass alle Unterelemente konstant bleiben. Man kann ja beliebig Referenzen auf diese erstellen, beziehungsweise die Referenzen können schon existieren. Darüber kann man die Unterlemente ändern.
dedlfix.
gudn tach!
Es kommt auf die eigentliche Aufgabenstellung an. Das Problem tritt doch nur auf, wenn
key
kein bekannter konstanter Wert ist, also aus einer unbekannten Quelle kommt.
genau. das ist bei mir der fall. der key kommt aus einem freitextfeld. (im minimalbeispiel hattee ich das vernachlaessigt, weil es mir um den allgemeinen fall ging.)
In dem Fall ist etwas mehr Aufwand nötig, um ihn für alle Werte sicher einsetzen zu können.
meinst du damit den check mittels hasOwnProperties() oder noch mehr aufwand als das?
Ja, Map gibt es auch. Wenn man nur einen einfachen Key-Value-Speicher braucht, kann man das nehmen. Objekte haben noch andere Eigenschaften. Das muss man für seinen konkreten Fall klären, was da sinnvoller ist.
gesucht war in meinem fall eine entsprechung eines hashes (in perl) bzw. einer map (in c++). dafuer scheint mir Map eher zu passen.
interessant finde ich auch die loesung, die kai345 vorschlaegt.
ah, das const, bezieht sich nur auf die oberste ebene des objekts und nicht auf die properties, ok. finde ich nicht intuitiv, aber gut zu wissen.
Muss aber so sein. Man kann nicht garantieren, dass alle Unterelemente konstant bleiben. Man kann ja beliebig Referenzen auf diese erstellen, beziehungsweise die Referenzen können schon existieren. Darüber kann man die Unterlemente ändern.
naja, in c++ ist es halt anders. wenn ich da ein objekt als const bezeichne, dann sind auch grundsaetzlich dessen eigenschaften fixiert.
prost
seth
Hallo dedlfix,
Ja, Map gibt es auch.
Nein, Map gibt's genau dafür. Leider noch nicht sooo lange, aber immerhin kennt es der Internet Explorer 11 und darum sollte man dieses Objekt dringend empfehlen.
Der Begriff des assoziativen Arrays ist ohnehin fragwürdig. In PHP gibt's den, weil da der Array-Typ so weit gefasst ist, dass er als Hash oder Dictionary herhalten kann.
In JavaScript kann man plain objects verwenden, um Hashes oder Dictionaries zu implementieren, aber man darf nicht den Meißel als Schraubendreher verwenden (oder umgekehrt).
myHash=Object.create(null)
aufruft, das erzeugt ein Objekt ohne Prototyp. Dann gibt's keine störenden Properties mehr, aber auch kein Basis-Set an Methoden wie hasOwnProperty. Statt dessen muss man Object.hasOwnProperty.call(myHash, 'foo')
aufrufen.if (myHash['foo'])
implementieren, sondern mit myHash.hasOwnProperty('foo')
. Genau dafür ist die Methode da.Wichtig ist aber die Erkenntnis, dass Plain Old Javascript Objects keine idealen Maps sind. Dafür gibt es das Map Objekt. Man muss gucken, welcher Browser welche Methoden unterstützt (bei MDN oder Kangax), und nach Bedarf Polyfills bereithalten.
Rolf
const some_object = new Map(); some_object.set('init', true); const key = 'constructor'; if(some_object.get(key)){ destroy_earth(); }
das sieht sauberer aus.
Alternativ, könnte man auch eine Funktion als Map benutzen:
const map = key => (
(key === 'foo') ? 42 :
(key === 'bar') ? 43 : undefined
)
console.assert(map('foo') === 42)
console.assert(map('bar') === 43)
console.assert(map('test') === undefined)
Solche funktionalen Maps kann man sich auch dynamisch zusammenbauen:
function empty(key) {
return undefined;
}
function set(key, value, map) {
return lookup => (key === lookup) ? value : map(lookup);
}
const map = set('foo', 42, set('bar', 43, empty))
console.assert(map('foo') === 42)
console.assert(map('bar') === 43)
console.assert(map('test') === undefined)
Ist aber syntaktisch leider nicht so schön und Lesezugriffe brauchen lineare Laufzeit.
der code-schnipsel
var some_object = {}; some_object['init'] = true; if(some_object['constructor']){ destroy_earth(); }
wuerde (wenn die funktion
destroy_earth
korrekt implementiert ist), fatale folgen haben.denn
some_object
besitzt als objekt standardmaessig die methodeconstructor
(sowie weitere methoden wietoString
etc.)
var some_object = Object.create(null);
…
gudn tach!
var some_object = Object.create(null);
oh, das ist ja cool. ein objekt ohne eigenschaft. wusste nicht, dass das geht.
prost
seth