Apply è un’utile prototipo dell’oggetto Function che permette di modificare lo scope all’interno di una funzione ( ovvero a quale oggetto si riferirà this ) e di passare degli argomenti sotto forma di array; quest’ultima feature è molto interessante, poichè non esistono altri modi semplici per fare una cosa del genere; ad esempio potrebbe servire passare gli argomenti di una funzione a un altra funzione:
function caller() {
second.apply(this,arguments);
}
Purtroppo apply non funziona con le vecchie versioni del browser Microsoft, oltre a ciò, sempre su IE, apply non funziona sui metodi nativi ma solo sulle funzioni crete dal programmatore.
Il metodo più usato per simulare apply è utilizzare eval:
function caller() {
/*ATTENZIONE: questo codice non funziona veramente;
prima di usare eval sarebbe necessario copiare le voci
di arguments in un vero array; arguments è un oggetto*/
second(eval(arguments));
}
Purtroppo eval ha vari svantaggi, tra questi il fatto che se uno degli argomenti è un oggetto salta tutto…
Non a caso il precedente esempio non funziona come dovrebbe, proprio perchè eval interpreta ogni oggetto come una stringa.
Che fare allora? A eval non si può rinunciare, ma vediamo di usarlo meglio questa volta!
Function.prototype.apply = Function.prototype.apply || function(thisObj, args) {
var evalArgs = "",
evalScope = "",
f = this,
res;
for(var i = 0, l = args.length; i!=l; i++) {
evalArgs += ‘args[’ + i + ‘]’;
if(args[i + 1]) evalArgs += ‘,’
}
if(thisObj) {
thisObj.__________apply_f = f;
evalScope = ‘thisObj.__________apply_’;
}
res = eval(evalScope + ‘f(’ + evalArgs + ‘)’) || null;
if(thisObj.__________apply_f) delete(thisObj.__________apply_f);
return res;
} Questa funzione si occupa di creare una stringa del tipo ‘a[1],a[2],a[3]’, passata poi alla funzione eval.
Oltre a ciò crea un metodo temporaneo dell’oggetto che poi viene cancellato, in modo da poter applicare la funzione con lo scope giusto.
Avevo pensato a una soluzione alternativa, ovvero controllare il numero di argomenti e regolarsi di conseguenza, ma forse in questi casi eval è meglio.