By Luca Greco a.k.a. "rpl"
la tentazione è forte...
DOH!!!!
ehhhh! non vi lamentate troppo pero'... il manuale parlava chiaro ;-)
Il modo corretto di iterare un array sino a Javascript 1.6 era il ciclo for con indice numerico (alla plain C maniera) mentre ora è possibile usare il metodo forEach:
Quante cose si imparano leggendo un manuale, no? ;-)
my_array = [2,3,4];
for (var i in my_array) {
print(i);
}
purtroppo... non avevate considerato questo... ;-)
>>> Array.prototype.remove = function (B) {
var A = this.indexOf(B);
if (A != -1) {
this.splice(A, 1);
}
return this;
}
>>> my_array.remove
function()
>>> for (var i in my_array) { console.log(i) }
0
1
2
remove
dopo aver aggiunto un metodo al prototype di Array ce lo ritroveremo in tutte
le istanze di Array:
DOH!!!!
ehhhh! non vi lamentate troppo pero'... il manuale parlava chiaro ;-)
Quindi scartate for e for each come metodi di iterazioni sugli Array Javascript... toglietevelo dalla testa ;-) (sono più utili per fare reflection sugli oggetti... Array compresi).(From "Core JavaScript 1.5 Reference:Statements:for...in") Although it may be tempting to use this as a way to iterate over an Array, this is a bad idea. Thefor...in
statement iterates over user-defined properties in addition to the array elements, so if you modify the array's non-integer or non-positive properties (e.g. by adding a"foo"
property to it or even by adding a method or property toArray.prototype
), thefor...in
statement will return the name of your user-defined properties in addition to the numeric indexes. Also, because order of iteration is arbitrary, iterating over an array may not visit elements in numeric order. Thus it is better to use a traditional for loop with a numeric index when iterating over arrays.
Il modo corretto di iterare un array sino a Javascript 1.6 era il ciclo for con indice numerico (alla plain C maniera) mentre ora è possibile usare il metodo forEach:
>>> my_array.forEach(function(e) { console.log(e); });
2
3
4
>>> Array.forEach(my_array,function(e) { console.log(e); });
2
3
4
Ma attenzione a quello che scrivete nella closure che passate a forEach:
>>> obj = { itera: function(a) { console.log(this); a.forEach(function(e) { console.log(this); }) } }
Object
>>> obj.itera([1,2,3]);
Object
Window
Window
Window
come è possibile verificare nel proprio Firebug this fuori dalla closure punta all'Object obj, mentre il this nella closure punta a Window (il contesto globale).
Un'ulteriore conferma di questo comportamento possiamo ottenerla con uno spidermonkey in linea di comando:
rpl@ubik:~$ js
js> obj = { itera: function(a) { print(this); a.forEach(function(e) { print(this); }) } }
[object Object]
js> obj.itera([1,2,3])
[object Object]
[object global]
[object global]
[object global]
Questo comportamento è un po' spiazzante (con un for o un for each non avremmo avuto un cambio di contesto del genere).
Personalmente risolvevo definendo come workaround una variabile self raggiungibile dalla closure per ricordare il contesto da cui ho avviato il forEach:
>>> obj = {
prova: function(a) {
var self = this;
console.log(this);
a.forEach(function(e) { console.log(self); })
}
}
Object
>>> obj.prova([1,2,3])
Object
Object
Object
Object
Ma ancora una volta facendo riferimento al manuale (RTFM RTFM RTFM RTFM!!!):
si può verificare che forEach accetta un secondo parametro allo scopo di selezionare il contesto (this) nel quale la closure sarà eseguita, che se non definito o nullo sarà associato al contesto globale (come verificato con gli snippet precedenti).
Detto in codice diventa:
>>> obj = {
itera: function(a) {
console.log(this);
a.forEach(function(e) { console.log(this); },this)
}
}
Object
>>> obj.itera([1,2,3])
Object
Object
Object
Object
Quindi la Soluzione (quella con la S maiuscola) è quella di passare this come secondo parametro della forEach.
Quante cose si imparano leggendo un manuale, no? ;-)
0 commenti:
Posta un commento