Krautkanal.com

Veröffentlicht am 2015-06-03 13:54:23 in /prog/

/prog/ 7168: Hallo Bernd, warum ist mein Array keys undefined, e...

franciscoamk Avatar
franciscoamk:#7168

Hallo Bernd,

warum ist mein Array keys undefined, es ist doch Global oder etwa nicht?


var keys = [];

document.body.addEventListener('keydown', function(e) { keys[e.keyCode] = true });
document.body.addEventListener('keyup', function(e) { keys[e.keyCode] = false });

function update(){
if(keys[38]){
console.log('jump');
}
}

var bla = setInterval(update, 10);


>Uncaught TypeError: Cannot read property '38' of undefined

okcoker Avatar
okcoker:#7169

>warum ist mein Array keys undefined
>var keys = [];
In welcher Sprache kann man "var" benutzen wenn in der dazugehörigen Zuweisung kein Typ existiert?

mugukamil Avatar
mugukamil:#7170

>>7168
Sieht doch gut aus.
Befindet sich die Variable 'keys' auch im selben Scope wie die Funktion 'update'?

johnriordan Avatar
johnriordan:#7171

> Definiere leeres Array
> versuche eventuell später an unterschiedlichsten Stellen Werte zu schreiben
> Lese 38stes Element
Es mag zwar sein, dass so ein Krebs Mittlerweile kompiliert oder ausgeführt wird.. aber nein! Warum nicht:
[code]var keys = new Array(128);[/code]
Oder wie groß es auch werden mag..

seanwashington Avatar
seanwashington:#7175

>>7168

>warum ist mein Array keys undefined

Kann es sein, dass du keys in einer Closure definiert hast und die Funktionen in einer anderen oder global?

Beispiel (jQuery):

// die übergebene Funktion wird bei document ready ausgeführt
$(function() {
// existiert nur innerhalb dieser Funktion
var keys = [];

// globale "Variable" (genauer: Property des globalen Objekts) setzen
blubb = [];
});

function bla() {
// Fehler: keys ist hier undefined!
if (keys[38]) {
// irgendwas...
}

// blubb ist vorhanden (das sagt aber noch nichts über das Element am Index 38 aus).
if (blubb[38]) {
// irgendwas...
}
}

>>7169

>In welcher Sprache kann man "var" benutzen wenn in der dazugehörigen Zuweisung kein Typ existiert?

JavaScript.

>>7171

>var keys = new Array(128);

In JS wird von den meisten Entwicklern die literale Schreibweise zum Erstellen bevorzugt, OPs Ansatz gilt also als besser. Man muss die Größe des Arrays nicht angeben.

woodydotmx Avatar
woodydotmx:#7177

Danke Bernd,

aber irgendwie scheint es an Chrome zu liegen. In FF funktioniert es, und in Chrome auch wenn ich das Array umbenenne.

mauriolg Avatar
mauriolg:#7178

>>7177
Der Code von OP funktioniert in Bernds Chrome auch ohne Umbenennung.

csteib Avatar
csteib:#7180

>>7171
Andere Sachen als Krebs bezeichnen, aber selber welchen liefern.
Es gibt gute Gründe nicht new Array() zu verwenden.

gojeanyn Avatar
gojeanyn:#7181

>>7180
Na dann schieß doch mal los!

slaterjohn Avatar
slaterjohn:#7182

>>7181
Nicht Vorbernd, aber neben schlechterem Aussehen kann es scheinbar auch zu schlechterer Performance führen.

http://stackoverflow.com/questions/7375120/why-is-arr-faster-than-arr-new-array

albertodebo Avatar
albertodebo:#7183

>>7171
Das Problem ist aber, dass keys selbst undefined ist, du Profientwickler.

irsouza Avatar
irsouza:#7184

>>7182
Hast du den Mikrobenchmark aus diesem Pfosten selbst mal ausgeführt? Bei diesem Bernd haben die Ergebnisse so eine riesige Varianz, dass es schon sehr mutig ist, daraus Schlüsse zu ziehen. Aber Bernd glaubt gerne, dass sich die Ausfürhungszeit der beiden Varianten tatsächlich um ca. 20% unterscheidet, auf Stackoverflow steht ja eine nachvollziehbare Erklärung dafür.

Trotzdem ist >>7180 nach wie vor eine Erklärung schuldig, denn 20ms Einsparung beim Erstellen von 200.000 Arrays fällt sicher nicht in die Kategorie "guter Grund". Und außerdem war ursprünglich die Rede von "new Array" mit Integer-Argument, was sich semantisch von "[]" unterscheidet und somit >>7180 noch peinlicher aussehen lässt.

ninjad3m0 Avatar
ninjad3m0:#7188

>>7184

>Trotzdem ist >>7180 nach wie vor eine Erklärung schuldig

>>7175 hier. Es wird allgemein empfohlen, die literale Schreibweise zu nutzen, um einheitlichen Code zu gewährleisten.

Das Problem ist, dass in JS folgendes möglich ist, die Ergebnisse aber unterschiedlich sind:

>var myStr = new String('blubb');
>var myStr2 = 'blubb';

Ähnlich auch mit Number und Object. Das Problem ist, dass bei einer Typüberprüfung von myStr "object" und nicht wie bei myStr2 "string" zurückgegeben wird. Deswegen ist es allgemein best practice, die literale Schreibweise zu nutzen (denn die new Varianten haben keine Vorteile).

>var myArr = new Array(4);

limitiert das Array auch nicht wie einige hier vielleicht annehmen auf vier Einträge, sondern füllt es lediglich mit vier leeren (undefined) Werten. Es kann trotzdem weiter hineingepusht werden. So ein Code verwirrt also mehr, als dass er Klarheit schafft.

mfacchinello Avatar
mfacchinello:#7196

>>var myStr = new String('blubb');
>>var myStr2 = 'blubb';
>
>Ähnlich auch mit Number und Object. Das Problem ist, dass bei einer Typüberprüfung von myStr "object" und nicht wie bei myStr2 "string" zurückgegeben wird.
Und was hat das nun mit new Array zu tun? typeof([]) == typeof(new Array()) == "object"

>>var myArr = new Array(4);
>
>limitiert das Array auch nicht wie einige hier vielleicht annehmen auf vier Einträge
Wer hat das denn behauptet?

"keys = new Array(128)" ist eine Optimierung, bei der es es darum geht,
1) häufige Vergrößerungen des Arrays zu vermeiden (dauert lange beim Einfügen) und
2) zu verhindern, dass das Array im Laufe der Benutzung zum Sparse Array wird (dauert u.U. lange beim Lesen und Einfügen).
Beide Effekte haben negative Auswirkung auf die Performance. Und sie sind beide Implementierungsdetails, die von unterschiedlichen VMs unterschiedlich implementiert werden. Je nach VM ist es denkbar, dass die "new Array(128)"-Optimierung keinen oder aber im besten Fall eine positive Auswirkung hat.

Schauen wir uns an, warum. Zu Effekt 1): Nehmen wir an, die VM dimensioniert den internen Speicher von Arrays immer so, dass gerade genug Platz für die aktuelle Anzahl an Elementen ist. Dann wird beim Ausführen folgender Schleife
var arr = [];
for (var k=0; k<128; i++) {
arr[k] = true;
}

der Speicher insgesamt 128 mal vergrößert. Speicher vergrößern ist im Gegensatz zu einem einfachen Schreibzugriff (z.B. arr[12] = 34 im Anschluss auf die obige Schleife) eine teuere Operation. Im schlimmsten Fall kann der aktuelle Speicherbereich nicht mehr vergrößert werden und es muss neuer, freier Speicher gesucht werden. Und nach irgendetwas suchen dauert meistens lang. Wird nun vor der obigen Schleife das Array mit arr = new Array(128) angelegt, hat die VM gleich zu Beginn die Gelegenheit, zusammenhängenden Speicher für 128 Elemente zu suchen. Alle Einfügeoperation im Inneren der Schleife werden damit zu einfachen Schreibzugriffen.

Zu Effekt 2): Javascript erlaubt folgendes Programm:
var arr = [];
arr[100000] = true;

Danach wird arr.length 100001 sein. Eine VM wird hier mit hoher Wahrscheinlichkeit die interne Datenstruktur des Arrays in eine Map-ähnliche Struktur ändern. Damit liegen die Daten nicht meer hintereinander in einem zusammenhängenden Speicherbereich, sondern werden einzeln zusammen mit ihren Indizes (also im obigen Beispiel 100000) abgelegt. Die VM vermeidet so das Reservieren eines riesigen Speicherblocks der Länge 100001. Das nennt sich dann Sparse Array. Die dafür geeigneten Datenstrukturen (Hash Tables, Suchbäume) sind zwar in der Regel sehr performant, aber niemals so schnell wie der Direktzugriff auf einen einen zusammenhängenden Speicherbereich. Auch hier stellt new Array(128) eine Optimierung dar, denn man hofft, dass es die VM davon abhält, das Array in ein Sparse Array umzuwandeln.

woodydotmx Avatar
woodydotmx:#7197

>>7196

>Und was hat das nun mit new Array zu tun

Dass man einheitlich programmieren sollte, auch wenn du mit typeof Array leider Recht hast.

>Wer hat das denn behauptet?

Ich habe nicht behauptet, dass es jemand behauptet hätte. Aber aus typischer Programmierersicht wäre es logisch.

>"keys = new Array(128)" ist eine Optimierung

Die von dir geschilderten technischen Details mögen alle zutreffen, jedoch halte ich den Performancenutzen in diesem Fall für absolut vernachlässigbar und würde die Einheitlichkeit des Sourcecodes höher gewichten. Desweiteren sollte eine gute VM in der Lage sein, zu analysieren, wie genau das Array im gesamten Code genutzt wird, was deine Argumentation dann wieder ad absurdum führen würde, oder?

mshwery Avatar
mshwery:#7198

>>7197
>Die von dir geschilderten technischen Details mögen alle zutreffen, jedoch halte ich den Performancenutzen in diesem Fall für absolut vernachlässigbar und würde die Einheitlichkeit des Sourcecodes höher gewichten.
Die Nachricht an den Leser des Source Codes ist für Bernd eindeutig:

[]: Eine Liste, deren Größe zum Zeitpunkt der Initialisierung noch nicht feststeht. Elemente werden mit push(), splice() und Co. eingefügt.

new Array(n): Ein Vektor der Länge n, dessen Größe sich nicht oder nur selten ändert. Die Elemente des Vektors werden per Arrayzugriff geschrieben.

In OPs Fall (arr[keyCode] = true) ist schon von vornherein klar, dass im Vergleich zur Größe des Arrays eher wenige Elemente geschrieben werden. Hier gilt es, sich zwischen einem Dictionary und einem Array zu entscheiden. Angesichts des begrenzten Wertebereichs der Indizes (Bernd nimmt mal an, dass der keyCode zwischen 0 und 256 liegt), ist ein Vektor eine perfekt auf diesen Fall passende Datenstruktur.

>Desweiteren sollte eine gute VM in der Lage sein, zu analysieren, wie genau das Array im gesamten Code genutzt wird, was deine Argumentation dann wieder ad absurdum führen würde, oder?
Entscheidungsproblem, kennste?

albertaugustin Avatar
albertaugustin:#7199

>>7198

>Die Nachricht an den Leser des Source Codes ist für Bernd eindeutig:

Es ging in erster Linie um Einheitlichkeit, nicht Eindeutigkeit. Muss man wirklich

>new Array(128)

schreiben und dann vielleicht ein paar Zeilen später

>{}

anstelle von

>new Object

?

Das ist doch insgesamt absurd und verwirrend, selbst wenn man dadurch 2ms sparen würde.

>Entscheidungsproblem, kennste?

Nein. Ich weiß aber, dass man solche Fälle rein theoretisch bereits durch statische Codeanalyse herausfiltern und optimieren könnte, sodass man sich nicht auf den u. U. verwirrenden Stilbruch mit new Array einlassen müsste. Beispiel: In OPs Code wird auf den Index 38 geprüft, also kann die VM davon ausgehen, dass das Array mind. 39 Elemente enthalten könnte.

Neuste Fäden in diesem Brett: