05 diciembre, 2009

No toquéis el "with"

En los últimos tiempos se ha satanizado la orden with, por parte de personas de renombre como el mismo Douglas Crockford. En su artículo With statement considered harmful explica que, a pesar de ser similar a otros lenguajes, la falta en JavaScript de que un bloque tenga un ámbito propio puede fomentar errores difíciles de detectar. Si dentro del bloque del with se asigna un valor a una variable, no hay forma de saber si se está haciendo sobre un miembro del objeto pasado con el with o si se está modificando una variable global:

var bing=1;
with(ooo.eee.ooo.eee.ooo) {
  bing=2;
}
// en este punto, que toma el valor 2? 
// bing==2 o ooo.eee.ooo.eee.ooo.bing==2
De hecho propone en sus recomendaciones para la próxima versión de ECMAScript que está orden sea declarada obsoleta. Sin embargo las cosas no son tan sencillas como parecen. De nuevo, Andrea Giammarchi le saca punta al asunto como ya hizo con la polémica del desconocido segundo parámetro de eval, acusando a los que lo quitaban del lenguaje de perder una oportunidad perfecta de generar un entorno controlado para ejecutar secuencias en las que no se confía. Y también pasó con la propuesta de eliminar callee ante la que Andrea defendió que no se hiciese. Con esta sencilla estructura se consigue mucha más potencia que con el uso tradicional pasando al with una variable con un objeto:
with({o:myreference}){
    o.doStuff();
    o.var1 = "loquesea";
    // etc etc ...
};
También se facilita construcciones commo la siguiente que resulta extremadamente compacta y, por tanto, poco susceptible de ganar espacio con una compresión de código tradicional:
with(document)
  with(documentElement)
    insertBefore(
      createElement("script"),
      firstChild
    )
    .text = "alert(1)"
;
Sólo que además permite aprovechar esa definición en línea del parámetro-objeto para realizar llamadas a funciones, usar el operador terciario ( condicion ? cierto : falso ), o especificar parámetros por defecto:
// ejemplo de argumentos con nombre y sin usar closures
with({
  obj:myObject,
  // valores por defecto en línea por si acaso
  collection:collection || [],
  callback:myCaseAnalyzer,
  // variables locales
  i:0,
  length:collection ? collection.length : 0,
  // variable local no inicializada
  tmp:null
}){
  for(;i < length; ++i){
    tmp = callback.call(obj, collection[i]);
    if(tmp){
      tmp.doStuff();
      collection[i] = tmp;
    };
  };
};
Que resulta ser equivalente a los típicos closures tan utilizados. Otro uso interesante sería la tradicional llamada Ajax:
with(this.XMLHttpRequest ?
  new XMLHttpRequest :
  new ActiveXObject("Microsoft.MSXML")
){
  open("get", "?ajax=true", true);
  onreadystatechange = function(){
    if(readyState === 4)
      // realiza acciones con responseText/XML
      alert(responseText)
    ;
  };
  send(null);
}

2 comentarios:

Anónimo dijo...

¿Quién es Douglas Crockford?

Àl dijo...

http://en.wikipedia.org/wiki/Douglas_Crockford
Douglas Crockford es un programador estadounidense y emprendedor, conocido principalmente por su implicación en el desarrollo del lenguaje JavaScript, y por haber popularizado el formato de datos JSON (JavaScript Object Notation).

Publicar un comentario en la entrada

Últimos links en indiza.com