<link href="css.css?<?=filemtime("css.css")?>" rel="stylesheet" type="text/css" >
Con esto, añade la hora/fecha de modificación a la URL de petición, de forma que obliga al navegador a solicitar una versión distinta sólo si consta que se ha modificado el archivo. Nótese que el documento en sí no pasa a través del servidor de aplicaciones y que el servidor web ignora lo que hay detrás del interrogante (?) pero al formar parte de la URL, no cuadra con la versión que hay en caché.
31 marzo, 2008
Evitar el cache en los archivos estáticos
29 marzo, 2008
Ext.ux. YoutubePlayer
26 marzo, 2008
SaveTheDevelopers.org
<script src="http://www.savethedevelopers.org/say.no.to.ie.6.js"></script>
25 marzo, 2008
mail-trends
Atributo hash
hash
en aquellos tags que también usen src
(como iframe
o img
) o href
(como a
). Dicho atributo contendría la codificación en base 32 del contenido al que apuntan y que cumpliría un doble propósito:
- servir de control de seguridad para comprobar que el contenido recibido se corresponde con el que se enlazó originalmente
- servir como índice para cachear contenido de forma que no se descargue multiples veces un mismo recurso aunque esté ubicado en localizaciones distintas
Shorty
24 marzo, 2008
Otras comunidades sociales Open Source
Google Ajax API de lenguajes
21 marzo, 2008
Lovdbyless
Probar la plataforma.
JSAwesome
Por ejemplo ...
new JSAwesome(
'rad', [['cool','neat'], ['^neat',true]],
{'cool': {label:'Cool man', validation:'cool'}}
).to_html()
...se convertiría en...
<label for="rad_cool">Cool man</label>
<input type="text" name="rad_cool" value="neat"/>
<label for="rad_neat"><input type="checkbox"
name="rad_neat" checked="checked"/> Neat</label>
... o sea...Descargar.
20 marzo, 2008
Google Visualization API
- Incorpora visualizaciones directamente en tu web
- Escribe, comparte y reutiliza visualizaciones
- Crea extensiones a productos Google
- Usa muchas fuentes de datos pero una API
Más en Information Aesthetics, en ArsTechnica, en Google Code, Galería de visualizaciones, y nuevas tablas pivotantes en Google Docs (llamadas dinámicas en Excel).
Los discos se han convertido en cintas
18 marzo, 2008
Auriculares marcianos
17 marzo, 2008
Respuestas automáticas en formato JSON para CakePHP
XHTML/CSS Markup Generator
XHTML/CSS Markup Generator es una herramienta que permite agilizar la creación de una nueva página XHTML obteniendo rápidamente un esqueleto organizado y fácil de modificar.
A brief introduction to Opacity and RGBA - CSS3
Con la nueva versión de CSS (v.3) la opacidad pasa de definirse así:
div { background-color: rgb(255,0,0); opacity: 1; }
a definirse con la nueva función rgba (red-green-blue-alpha):
div { background-color: rgba(255,0,0,1); }
Así se define junto con el color y además tiene la consecuencia de que los elementos hijos no la heredan (cosa que sí pasaba con opacity).
Traspaso a Blogger
JavaScript Convertidor a números romanos
16 marzo, 2008
John Resig - Busca pero no reemplaces
"foo=1&foo=2&foo=3&blah=a&blah=b"
en otra que así: "foo=1,2,3&blah=a,b"
.
function compress(data){
var q = {}, ret = "";
data.replace(/([^=&]+)=([^&]*)/g, function(m, key, value){
q[key] = (q[key] ? q[key] + "," : "") + value;
});
for ( var key in q )
ret = (ret ? ret + "&" : "") + key + "=" + q[key];
return ret;
Resulta muy interesante el uso de la función replace
con una función que recibe las partes clave y valor y cuyo resultado se reemplazará en la cadena a buscar. También es interesante la técnica para comprobar si se debe concatenar una pieza más a una cadena separada por una coma: ret = (ret ? ret + "&" : "") + value;
Portales de vídeo temáticos con la nueva API de YouTube
Con las APIs, por ejemplo, podrás realizar búsquedas de vídeos, automatizaciones de subidas de vídeos o actualizar y eliminar los datos de éstos. Tienes una guía definiendo todos los métodos de esta API en esta página web.
Además, YouTube también nos ofrece la posibilidad de no utilizar el visor Flash que estamos acostumbrados a ver cuando utilizamos el clásico 'código HTML embebido', y usar un visor Flash 'Chromeless' (completamente sin adornos) que permitirá integrarlo con el diseño de la página. Este visor viene acompañado de una librería JavaScript que incorpora eventos del visor que nos permitirán por ejemplo detener y reproducir el vídeo con controles hechos a nuestra medida, quitar el sonido, saber su duración, etc. Ver ejemplo.
También en Programa con Google.
Las elecciones y soitu.es
Diseñando para la web móvil
Designing for the Mobile Web
Crear una gran experiencia web para usuarios de dispositivos móviles es mucho más fácil de lo que podría pensarse. En este artículo se introducen 7 pasos fundamentales que, si se siguen, te ayudarán a evitar los problemas que han causado que otros sitios móviles fracasen. Al final del artículo conocerás exactamente dónde enfocar los esfuerzos para construir un sitio con éxito.
IE8 acelera las cosas
Flujos de datos separados para datos genéricos y de usuario
phplondon08 - El correo del `chico loco´
Firecookie
John Resig sobre Internet Explorer 8
Google Contacts Data API
Microsoft ya publicó en su momento su propio API de contactos. Y ahora vuelve a mover pieza : Parece que Microsoft se pone las pilas y se está planteando hacer frente a Google. Si es así, ganaremos todos.
Internet Explorer 8 beta 1 disponible
) al estilo XHTML en HTML, Web Slices, suscripciones a contenidos cambiantes basados en el microformato hAtom y 6 conexiones por host (antes 2) que debería facilitar el desarrollo de Comet (conexiones persistentes con el servidor).Visitar o descargar. Via Simon Willison
xssinterface
Funciona aprovechando la interfície postMessage() de HTML5 si está disponible o simulándola de forma transparente en los navegadores actuales (aprovechando Google Gears si está instalado o una hack basado en cookies).
function sayHello() {
var caller = new XSSInterface.Caller("www.listener.com","/xssinterface/html/cookie_setter.html","channel1");
caller.call("hello", "Hello World")
}
Y en el mismo iframe cargado:
window.xssListener = new XSSInterface.Listener("1234567890","channel1");
window.xssListener.allowDomain("www.caller.com", "/xssinterface/html/cookie_setter.html", "/xssinterface/js/gears_listener.js");
window.xssListener.registerCallback("hello", function (msg) { $('output').value = msg} )
window.xssListener.startEventLoop()
XML con CouchDB
No hace tanto, la misma base de datos CouchDB abandonó XML a favor de JSON como formato para almacenar la información, lo que hizo que el proyecto ganase muchos adeptos. Ese cambio hacia Javascript ahora habilita de nuevo XML lo que demuestra que fue la mejor decisión posible. En cualquier caso, unas excelentes noticias para quienes quieren usar XML con todas las ventajas y novedades que supone esta innovadora base de datos.
Copio el ejemplo mostrado en el post:
by_lang: function(doc) {
var html = new XML(doc.content);
map(html.@lang, {title: html.head.title.text(), …});
}
El funcionamiento a la vista de Ward Cunningham
La idea es poder visualizar (de ahí la transparencia) el proceso que realizan los datos dentro de una aplicación típica mostrando paso por paso cómo sigue la lógica de negocio en un diagrama. De esa forma se da seguridad al proceso, el usuario entiende mejor lo que está haciendo y las mejoras resultan más evidentes para quienes usan las herramientas.
Los ejemplos mostrados son:
- guión de cambios a realizar (el proceso que se va a visualizar)
- La ejecución de ese proceso en el sistema, mostrando los formularios tal y como los ve el usuario durante el proceso.
- La visualización del resultado mostrado en un diagrama clasificado horizontalmente por los diferentes actores y verticalmente por la secuencia de tiempo.
Google Gears de bolsillo: descárgate información en tu móvil y trabaja offline
Via Google Dirson.
SQLite para Symbian
Sam Ruby: Truco PHP
?>
final de cierre de un archivo PHP ya que es opcional. Además, es preferible no cerrarlo para evitar espacios no deseados después del cierre que muchos editores de texto añaden, creando problemas posteriormente.
Microsoft da marcha atrás con IE8
Sin duda, es la mejor decisión y la que menos romperá la web. Ojalá forme parte de esa nueva actitud de Microsoft que nadie se ha creido.
Comentar un bloque de código usando un sólo carácter
Código comentado:
/*
dosomething();
// */
Código funcional con una sola barra:
//*
dosomething();
// */
También con comentarios de bloque:
Código comentado:
/*/
min-height:100px;
/**/
Código funcional con un sólo asterisco:
Código comentado:
/**/
min-height:100px;
/**/
Internet Explorer 8.0 beta para todos el 5 de Marzo
¿Qué hay de nuevo en ECMAScript 4.0?
Como funcionan los temporizadores en Javascript
Abrir sesión en sitios web sin introducir usuario ni contraseña
Los conocidos certificados de usuario, que algunos hemos usado para firmar documentos ante la administración, pueden servir para autenticarnos en unas pocas páginas web.
Tal y como cuenta el autor, yo también tengo una cuenta en myopenid.com así que me he instalado sin problemas el certificado de usuario que ofrecen. Es el método ideal para entrar en un sitio de la forma más cómoda posible, aunque sólo debe instalarse el certificado en equipos que sólo controlemos nosotros.
Ojalá se extendiese su uso. Mientras tanto, recomiendo usar este bookmarklet, que genera una contraseña única para cada sitio web visitado a partir de una clave maestra que no hemos dado a nadie y que es lo único que habría que recordar (aunque resida dentro del bookmarklet y no sea necesario introducirla cada vez).
Parseo de JSON nativo
Decodificando JSON:
YUI 2.5.0 - Nueva versión de la librería Yahoo! User Interface
Tutorial de SMSs
Este tutorial provee información sobre el desarrollo de aplicaciones con SMS. Empieza con una introducción de las tecnologías de mensajes entre móviles como SMS, SMS concatenados y EMS. Aprenderás lo que es un SMS, qué causa que los SMS sean tan populares, qué aplicaciones se pueden desarrollar con tecnología SMS, lo que son pasarelas y centros SMS, y algunos conceptos básicos sobre mensajes SMS.
Después se discutirá en detalle las distintas formas de enviar y recibir mensajes SMS desde un ordenador, las ventajas y desventajas de cada manera, lo qué son los proveedores de servicio SMS, el hardware (como módems GSM / GPRS) y el software (como HyperTerminal) requerido para enviar y recibir mensajes desde un ordenador, y dónde encontrar algunas herramientas y librerías gratuitas de mensajería SMS.
El libro negro de la programación gráfica
Navegadores web y el consumo de memoria
antrix.net recently
moo.rd - Una extensión para MooTools
Está diseñada para dar funcionalidades potentes y útiles a los desarrolladores, como un montón de efectos, estándares personalizables, funciones nativas de utilidad, gestión de tablas, cajas virtuales y algunas más.
Además, moo.rd es modular, flexible, y completamente compatible con MooTools.
Ver los ejemplos.
Constructores en Javascript considerados ligeramente confusos
En javascript, cada objeto tiene una propiedad constructor que se refiere a la función constructor que inicializa el objeto.Suena bien: hace que los constructores parezcan estáticos como las clases en Java. Incluso la sintaxis
new Constructor()
parece igual:
function MyConstructor() {}
var myobject = new MyConstructor();
myobject.constructor == MyConstructor; // true
Pero la vida no es tan simple:
function MyConstructor() {}
MyConstructor.prototype = {};
var myobject = new MyConstructor();
myobject.constructor == MyConstructor; // false
¿Qué pasa? Algunas definiciones
Objetos y métodos
Los objetos en Javascript son simples bolsas de propiedades con nombre que pueden ser leidas y escritas. Para la mayoría de propósitos, javascript no tiene clases. [1]Las funciones en javascript son objetos de primera clase. Los métodos en javascript son sólo propiedades que son funciones.
Prototipos
El prototipo (prototype) de un objeto es una propiedad interna a la que me referire como "[[Prototype]]" (como en Ecma-262). En otras palabras,obj.prototype
en general no es el [[Prototype]] de obj
. El estándar no provee una forma de recuperar la propiedad [[Prototype]] de un objeto.Los objetos javascript pueden delegar propiedades a su [[Prototype]] (y su [[Prototype]] puede hacer lo mismo; y así hasta Object Prototype).
Búsqueda de propiedades
Cuando una propiedad "propname" de un objeto es leida, el sistema comprueba si ese objeto tiene una propiedad llamada "propname". Si esa propiedad no existe, el sistema comprueba el [[Prototype]] del objeto para encontrar la propiedad, y así recursivamente.Esto significa que los objetos que comparten un mismo [[Prototype]] tambien comparten las propiedades definidas en ese [[Prototype]].
Cuando una propiedad "propname" de un objeto se establece, la propiedad se inserta en ese objeto, ignorando la cadena [[Prototype]] de ese objeto (y ocultando cualquier propiedad del mismo nombre en la cadena de prototipos).
La propiedad [[Prototype]] se inicializa desde la propiedad (pública) "prototype" de la función constructor, cuando ésta es llamada.
¿Qué está pasando? Línea por línea.
Esto es lo que las propiedades prototype y [[Prototype]] parecen. Las elipses son objetos, las flechas son propiedades que referencia a otros objetos. La/s cadena/s [[Prototype]] están en verde.#1: function MyConstructor() {}
Bastante simple.
MyConstructor.prototype
es una propiedad que es automáticamente creada, la cual en cambio tiene una propiedad constructor
que apunta a MyConstructor
. Recuerda eso: los únicos objetos que de hecho tienen una propiedad constructor
por defecto son las propiedades de funciones prototype
que se crean automáticamente.El resto no es realmente relevante pero podría confundir e iluminar (con suerte en ese orden):
El [[Prototype]] de
MyConstructor
es Function.prototype, no MyConstructor.prototype
. Nótese también que la cadena [[Prototype]] de cada objeto termina en el Object.prototype
.El [[Prototype]] de
Object.prototype
es realmente null
indicando que es el final de la cadena.
Para los siguientes pasos, estoy dejando la cadena [[Prototype]] de MyConstructor
por claridad, ya que no cambia y no es relevante.
#2: MyConstructor.prototype = {}
Ahora hemos terminado con el objeto
MyConstructor.prototype
predefinido y lo hemos sustituido con un objeto anónimo, mostrado aquí como "{}". Este objeto no tiene propiedad constructor,
#3: var myobject = new MyConstructor()
De este grafo, siguiendo las reglas de búsqueda de propiedades, podemos ahora ver que myobject.constructor es delegado a Object.prototype.constructor, el cual apunta a Object. En otras palabras:
function MyConstructor() {}
MyConstructor.prototype = {};
var myobject = new MyConstructor();
myobject.constructor == Object
¿Y qué pasa con instanceof
?
Javascript facilita el operador instanceof que pretende comprobar la cadena de prototipos del objeto con el que estás tratando. A partir de lo de antes, podrías pensar que lo siguiente devolvería false
:
function MyConstructor() {}
MyConstructor.prototype = {};
var myobject = new MyConstructor();
myobject instanceof MyConstructor // true
Pero el hecho es que funciona (pulsa el botón). También nota que myobject delega en Object.prototype:
function MyConstructor() {}
MyConstructor.prototype = {};
var myobject = new MyConstructor();
myobject instanceof Object
Cuando se llama a
instanceof
, comprueba la propiedad prototype
del constructor dado y comprueba la cadena [[Prototype]] del objeto dado. En otras palabras, no depende de la propiedad constructor
.Todo muy bonito, pero tu puedes aún romperlo si lo intentas con ganas:
function MyConstructor() {}
var myobject = new MyConstructor();
MyConstructor.prototype = {};
[ myobject instanceof MyConstructor, // false !
myobject.constructor == MyConstructor, // true !
myobject instanceof Object ] // true
Así quedan las cadenas de prototipos tras ejecutar eso:
Los constructores no son clases
En un sistema de objetos basado en clases, las clases típicamente heredan de otras, y los objetos son instancias de esas clases. Los métodos y propiedades que son compartidos entre instancias son (al menos conceptualmente) propiedades de clases. Las propiedades (y para algunos lenguajes, métodos) que no deben ser compartidos son propiedades de los mismos objetos.Los constructores de javascript no hacen nada parecido: de hecho los constructores tienen su propia cadena [[Prototype]] completamente separada de la cadena [[Prototype]] de objetos que ellos inicializan.
Los constructores no funcionan como inicializadores basados en clases
Una llamada a constructor asocia un nuevo objeto con un [[Prototype]]. La función constructor podría establecer propiedades adicionales sobre el objeto. Las llamadas a constructor no llaman constructores "heredados", y no deberían porque el [[Prototype]] del objeto (elprototype
del constructor) se supone que está compartido y (probablemente) ya inicializado.
Los constructores sólo son funciones
Cualquier función definida por el usuario en javascript automáticamente obtiene una propiedadprototype
que, en cambio, tiene una propiedad constructor
que se refiere (de vuelta) a la función.Cualquier función definida por el usuario puede ser llamada como constructor anteponiéndole
new
a la llamada. Esto pasará un nuevo objeto this
a la funcion, y su propiedad [[Prototype]] se inicializará a la propiedad prototype
de la función.
Notas al pie
[1] Hay clases definidas por el sistema: Function, Object, Array, Class, RegExp, Boolean, Number, Math, Date, Error y String. Un usuario no puede añadir una nueva clase, aunque el sistema podría definir más. Nótese que estas clases no son las misma que los objetos predefinidos (constructores) con el mismo nombre, y no pueden ser directamente accedidas de ninguna forma.Un constructor definido por el usuario que no devuelve explícitamente algo más siempre devuelve un objeto de la clase Object.
Referencias
A comp.lang.javascript question
Subject: "x.constructor == Foo" vs "x instanceof Foo".
Message-ID: <fniu6a$2cn$1@reader2.panix.com
>
http://groups.google.com/group/comp.lang.javascript/msg/102ab20c68aa738f
Ecma-262
Standard ECMA-262. ECMAScript Language Specification 3rd edition (December 1999) http://www.ecma-international.org/publications/standards/Ecma-262.htm
Flanagan 2006
JavaScript: The Definitive Guide, Fifth Edition. ISBN 10: 0-596-10199-6 | ISBN 13:9780596101992
Author & copyright
(c)2008 Joost Diepenmaat, Zeekat Softwareontwikkeling.
MooTools Swiff
Funciones `parciales´ con Javascript
Function.prototype.partial = function(){
var fn = this, args = Array.prototype.slice.call(arguments);
return function(){
var arg = 0;
for ( var i = 0; i < args.length && arg < arguments.length; i++ )
if ( args[i] == undefined )
args[i] = arguments[arg++];
return fn.apply(this, args);
};
};
// Y UN EJEMPLO DE USO
String.prototype.csv = String.prototype.split.partial(/,\s*/);
var results = "John, Resig, Boston".csv();
alert( results[1] ); // IMPRIMIRIA "Resig"
Con esto, es sencillo crear funciones nuevas a partir de las existentes. Existen en el artículo otras técnicas que amplían aún más la funcionalidad (como por ejemplo el rellenar automáticamente los parámetros que no se especifiquen).
Pro Javascript Design Patterns
Javascript namespaces
// creando la estructura anidada manualmente es engorroso
var com = {
thinkweb2: {
projects: {
namespace: 'una propiedad anidada'
}
}
}
com.thinkweb2.projects.namespace // => una propiedad anidada
La función es la siguiente y no tiene dependencias.
String.prototype.namespace = function(separator) {
var ns = this.split(separator || '.'), p = window;
for (var i = 0; i < ns.length; i++) {
p = p[ns[i]] = p[ns[i]] || {};
}
};
Thrudb - faster, cheaper than SimpleDB - igvita.com
ThruDB provee un conjunto consistente de servicios: Thrucene para indizar, Throxy para particionar y balancear la carga, y Thrudoc para almacenar los documentos.
Efectivamente, se trata de otro proyecto del estilo de CouchDB y del criticado servicio de Amazon, SimpleDB.
10 años de XML
Via ongoing · XML People y Anarchaia.org.
Herencia en Javascript basada en "clases"
function extend(subclass, superclass) {
function Dummy(){}
Dummy.prototype = superclass.prototype;
subclass.prototype = new Dummy();
subclass.prototype.constructor = subclass;
subclass.superclass = superclass;
subclass.superproto = superclass.prototype;
}
Hay que decir que la versión original viene de un tutorial de Kevin Lindsey. En realidad librerías como MooTools, jQuery, Dojo o Prototype ya incluyen una versión de esa función pero nunca está de más tener una versión independiente.
En este otro artículo del mismo autor se profundiza mucho más, facilitando una extensa guía para portar clases Java a Javascript.
Mensajes entre ventanas
Este sería el iframe emisor:
Y este el receptor:
Send me a message!
Via John Resig - Cross-Window Messaging
Delegación de eventos fácil con jQuery
onclick
, se busca dicha función en su elemento padre, y así sucesivamente hasta llegar al elemento body
. Este mecanismo se llama emergencia de eventos o event bubbling y puede ser aprovechado para definir las funciones de tratamiento de eventos sobre un elemento padre y que se aplique sobre todos los hijos a la vez, tal y como se explica aquí.
Esta sería una forma tradicional de realizarlo con jQuery:
$('#thing').click(function(e) {
var target = $(e.target);
if (target.hasClass('quit') return doQuitStuff();
if (target.hasClass('edit') return doEditStuff();
// and so on...
});
Esto se puede simplificar definiendo una función de delegación:
jQuery.delegate = function(rules) {
return function(e) {
var target = $(e.target);
for (var selector in rules)
if (target.is(selector)) return rules[selector].apply(this, $.makeArray(arguments));
}
}
Que se utilizaría de la siguiente forma:
$('#thing').click($.delegate({
'.quit': function() { /* do quit stuff */ },
'.edit': function() { /* do edit stuff */ }
}));
La función simplemente recorre las reglas comprobando si el elemento que disparó el evento pertenece a un selector y lanzando la función correspondiente pasándole el objeto evento.
Via danwebb.net - Event Delegation Made Easy In jQuery.
Incremental Map/Reduce en CouchDB
El ejemplo siguiente crea sus propias operaciones de combinación dentro de la función Reduce. Supongamos que tenemos una base de datos llena de recibos y queremos calcular el total gastado en un mes:
// este sería un recibo de ejemplo
{
"_id":"2DA92AAA628CB4156134F36927CF4876",
"type":"recibo"
"amount":19.95,
"note":"esto funcionara",
"year":2008,
"month":1,
"day":12,
....
"}
}
// a continuación la función Map
function (doc) {
if (doc.type == "recibo") {
var key = [doc.year, doc.month];
emit(key, doc.amount);
}
}
// y una función Reduce para calcular los totales de los recibos:
function (date, values) {
var result = {totalSpent:0, numPurchases:0};
for(var i=0; i<values.length; i++) {
switch (typeof values[i]) {
case "number":
result.totalSpent += values[i];
result.numPurchases++;
case "object":
// este es un objeto, y salida de una reducción anterior
result.totalSpent += values[i].totalSpent;
result.numPurchases += values[i].numPurchases;
}
}
return result;
}
// Una vez guardado en un documento de diseño, se pueden obtener los valores de Enero de 2008:
// GET /db/_view/receipts/amount_spent_month?key=[2008,1] //Resultado:
{"total_rows":12,
"rows":[
{ "key":[2008,1],
"value": { "totalSpent": 1252.1
"numPurchases": 13}
}
]
}
Una propuesta: mapear el email a una URL
- Se introduce una URL propia
- El servicio al que se intenta acceder consulta en esa URL quién provee OpenID
- El proveedor solicita la clave para esa URL que demuestre que se es el propietario.
Via Simon Willison.
Rastrea la historia del navegador para mejorar la experiencia del usuario
Crea un mapplet a partir de un mashup de Google Maps
cabel.name: FancyZoom 1.0
Google, IBM, Microsoft, VeriSign y Yahoo! se adhieren al estándar OpenID
Douglas Crockford: Los hilos son malos
Un bucle inter-lenguaje de tercer nivel
A Neighborhood of Infinity: A Third Order Quine in Three Languages. Visto en Anarchaia.org.
Emezeta Hoja de referencia para PHP
Emezeta Card PHP Cheat Sheet es una chuleta u hoja de referencia para PHP. Es la más completa que conozco. Con diferencia.
Via aNieto2K.
Idea sobre SQL sobre Javascript
table1 = { rows: [ {a:1, b:2} , {a:1, b:5} , {a:1, b:3} , {a:5, b:7} ] } // definición del conjunto de datos
// un from filtra los objetos con los que vamos a trabajar
from(table1)
> { rows: [ {a:1, b:2} , {a:1, b:5} , {a:1, b:3} , {a:5, b:7} ] }
// el where se especifica con la potencia de una función javascript
from(table1).where( function(row){return row.a==1} )
> { rows: [ {a:1, b:2}, {a:1, b:5} , {a:1, b:3} ] }
// finalmente el select indica que campos se "copian" del objeto filtrado resultante
from(table1).where( function(row){return row.a==1} ).select('b')
> [ {b:2},{b:5},{b:3} ]
// la ordenación es simple también
elms= from(table1).where( function(row){return row.a==1} ).select('b').orderby('b')
> elms= [ {b:2},{b:3},{b:5} ]
// así se accedería a la estructura resultante
elms[2].b
> 5
ElasticDB - (Amazon Elasticdrive + CouchDB)
- Un servidor de base de datos de documentos (CouchDB), accesible via una API RESTful basada en JSON.
- Sin esquemas y con un espacio de direcciones plano. (todo en una tabla).
- Replicación incremental robusta distribuida con gestión y detección bidireccional de conflictos.
- Consultable e indexable, con un motor de informes orientado a tabla que usa Javascript como lenguaje de consulta.
Acerca de CouchDB
A diferencia de las bases de datos SQL que están diseñadas para almacenar y hacer informes sobre datos fuertemente estructurados e interrelacionados. CouchDB simplifica grandemente el desarollo de aplicaciones orientados típicamente colaborativas (como CRM, gestores de contactos o teléfonos, foros, wikis o gestores de documentos, informes de gastos, e-mail o aplicaciones de asistencia). [...] Con CouchDB, no se sigue ningún esquema, así que nuevos tipos de documentos con nuevo significado pueden añadirse junto a los viejos. El motor de presentación está diseñado para manejar fácilmente nuevos tipos de documentos y documentos similares pero distintos. CouchDB se ha construido desde el principio con una visión consistente de un sistema de bases de datos distribuidas. A diferencia de los intentos engorrosos de embutir características distribuidas sobre los mismas bases de datos. Es el resultado de un diseño, ingeniería e integración cuidadosos creados de la nada. Los modelos de documento, vista, seguridad y replicación y la eficiente y robusta disposición en disco se han diseñado para trabajar juntos por un sistema fiable, eficiente y fácil de usar.JavaScript Library Techniques
Entrevista a Simon Willison sobre OpenID
PHP.js, Javascript con nomenclatura PHP
Javascript/Ajax cheat sheets
Reescribe la web con Chickenfoot
go("http://www.google.com/")
click("Images")
go("http://images.google.com/imghp?hl=en&tab=wi")
enter("Sign in", "koalas")
click("Search Images button")
go("http://images.google.com/images?hl=en&q=koalas&btnG=Search+Images
&gbv=2")
SitePoint
tinypy 64k
Los navegadores en 2009
Un más que interesante análisis del coste de desarrollar con ciertos navegadores y el beneficio asociado a ello. Por ejemplo, los de Microsoft tienen un coste altísimo debido a la infinidad de errores que generan, pero por desgracia son los más usados por los usuarios por lo que de alguna forma el esfuerzo se ve compensado. Esto mejora terriblemente con Firefox, que da muy pocos problemas pero tiene una base de usuarios grande. Via John Resig - The Browsers of 2009
El estado de JSON
Google Maps clusterer
- Sólo los marcadores visibles actualmente son creados.
- Si demasiados marcadores serán visibles, entonces se agrupan en marcadores agrupados.
Sustituye el objeto Console para evitar problemas al depurar con Firebug
Console
si no está creado para que no dé errores en caso de no existir:
if (! ("console" in window) || !("firebug" in console)) {
var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group"
, "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
window.console = {};
for (var i = 0; i < names.length; ++i) window.console[names[i]] = function() {};
}
Via aNieto2K y Glibness.
CouchDB más JSON más Helma
var c = new CouchDB('testing','localhost',8888);
c.createDb();
c.save({ title:'Testing', content:[1,2,3] });
¡Felicidades! Has creado una nueva base de datos y has creado un documento JSON en ella.
Comet funciona y es más fácil de lo que piensas
dojo.require("dojox.cometd");
jQuery(function($) {
dojox.cometd.init("http://example.com/cometd");
dojox.cometd.subscribe("/slideshow/change", function(comet) {
$('#currentSlide').attr('src', comet.data.src);
});
});
Y ya está ;-). Suscribirse al canal y una función para actuar cuando recibe un mensaje JSON.
Una fuente Atom dentro de código HTML
Megadeth Show Last Night
Posted by Chris on June 4th
Went to a show last night. Megadeth.
It was alright.
...en este otro, que se ve igual en el navegador, pero que siguiendo el microformato hAtom se consigue introducir información semántica (significado) dentro del código xHTML...
Megadeth Show Last Night
Posted by
Chris
on
June 4th
Went to a show last night. Megadeth. It was alright.
Ahora, como los lectores de feeds aún no aceptan código xHTML, nos tocará pasar por un conversor online (Subtlety) para obtener la fuente Atom sin haberla tenido que escribir a parte.
Más en Feeds for Free > err.the_blog.
Manejo de errores en javascript
Blob Sallad, un juego con simulación de físicas en JavaScript
En Opera Developer Community han realizado una pequeña demo que, aprovechando la etiqueta canvas de los navegadores modernos (un recuadro en el que se puede dibujar), han creado una simulación que implementa leyes físicas para que un conjunto de objetos reaccionen como en la realidad al colisionar entre sí.
API de Flickr: flickr.places.findByLatLon
Jaxer
runat="server"
o runat="both"
que indicarían que el código se puede ejecutar también en el lado del servidor. El siguiente ejemplo muestra un textarea
al usuario y al mismo tiempo permite guardar lo que el usuario introduzca en un archivo del servidor.
< html>
< head>
< /head>
< body onserverload="load()">
< /body>
< /html>
El que mejor lo describe es Chris Zumbrunn (Helma):
Se trata básicamente de Mozilla corriendo detrás de Apache en el lado del servidor, pero extendido con la funcionalidad del servidor que podrías esperar (API ), como leer y escribir archivos, acceder a bases de datos y otra comunicación externa. Pero dado que la parte del servidor se ejecuta dentro de un entorno de navegador completo, que incluye no sólo el DOM sino también CSS y toda la funcionalidad Javascript del cliente, incluyendo peticiones XMLHTTP y todo lo demás. Así puedes trabajar en ambos lados sin estar cambiando de estado mental continuamente.
Acceso al DOM y Javascript en el servidor.
Comunicación transparente entre navegador y servidor.
Accede a páginas creadas con otros lenguajes.
Comparte código de validación en cliente y en servidor.
Acceso a ficheros, bases de datos y sockets desde Javascript.
e4xd and jhino - javascript server-side soft-coding
DOCTYPE y compatibilidad futura
Addendum: Parece que hay mucho revuelo en el sector con la propuesta que viene de Microsoft. Tal y como comenta John Resig (jQuery), los ejemplos del artículo original incluyen otros navegadores a parte de IE, los cuales, de seguir esta propuesta, estarían limitando su mercado y comprometiendo sus posibilidades de seguir creciendo. Esta gente de Microsoft parece que siempre va con segundas. Su incapacidad para adaptarse a los estándares la intentan compensar intentando frenar el progreso a cualquier precio. La industria debería quitarles la importancia que ahora tienen porque están dando sobradas muestras de no tener ni idea sobre cómo utilizarla positivamente. Lo más divertido de todo es que los desarrolladores podrían utilizar una característica así para que los avances del Internet Explorer nunca lleguen a los usuarios. Se acostumbran a trabajar para una versión, la especifican en sus documentos y se olvidan para siempre de la rotura de las páginas por los cambios en las nuevas versiones. Como ha dicho Andy Budd es lo más parecido a dispararse en el pie y darse por muerto.
Addendum: Este artículo es el que mejor define hasta el momento la situación en la que se encuentra Microsoft. Todas las alternativas son malas y proponer ese engendro es su única salida viable para no dejar morir al navegador. Ellos solitos se han metido en el problema y ahora quieren arrastrar a toda la industria con ellos. Merecen dejar de ser relevantes para cualquier futuro estándar web.
Addendum: Chris Wilson, el responsable de desarrollo de IE ha aclarado, algo tarde, que con el nuevo
DOCTYPE
de HTML5 ( ) disparará automáticamente el modo de estándares haciendo totalmente innecesario especificar explícitamente el tag que Microsoft quiere introducir si se genera un documento correcto. Eso subsana la mayoría de las preocupaciones surgidas con la propuesta, tal y como afirma Resig.
MooTools 1.2 Beta 2
store
y retrieve
.
El diario inglés Telegraph proveedor de OpenID
Consejos para acelerar la descarga de páginas web
Desarrollando una aplicación con SimpleDb
- No hay ordenación, lo que obliga a realizar continuamente toda clase de rodeos para evitar esta característica. Además prácticamente obliga a devolver todos los registros para poder hacer la ordenación manualmente.
- Los datos están limitados a 1024 bytes. La solución no es trivial, si se pretende segmentar la información en bloques de ese tamaño, no hay garantías de volver a obtener la información correcta al no existir ordenación (punto anterior). La alternativa es usar Amazon S3 para estos casos, pero parece demasiado engorroso.
- No hay identificadores autoincrementales, por lo que hay que apañarselas para generar cadenas únicas que identifiquen los registros. La hora exacta actual puede ser una buena idea.
- No hay consistencia, por lo que la información puede tardar hasta 20 segundos en verse reflejada por parte de Amazon. Eso quiere decir que si después de insertar información se vuelve a cargar una página (algo que hacemos casi todos siempre), es posible que el dato acabado de introducir no aparezca con lo que ello implica.
- No hay tipos. Lo cual puede verse como algo positivo, pero que no lo es tanto cuando se echa a faltar el "null", lo que distingue la falta de valor en un campo. Eso implica que al introducir un nuevo campo en una tabla hay que inicializar el valor en todos los registros existentes.
- No es posible obtener multiples filas de datos. Para la aplicación que ha creado Alex, mostrar la primera página le requiere obtener todos los registros de la tabla de hilos y también todos los registros de la de mensajes, debido una vez más a que no existe ordenación. Esto puede además disparar la factura que se le paga a Amazon mensualmente, ya que son factores el ancho de banda y el número de consultas.
Amy Editor
Amy Editor es un editor online de código fuente para desarrolladores. Soporta JavaScript, Ruby, PHP, C#, Java, HTML, YAML, etc. Tiene resaltado de sintaxis, indentación inteligente para cada lenguaje, deshacer (undo) ilimitados, atajos de teclado personalizables, auto-completado de palabras (tecla ESC), etc.
También puede ser integrado fácilmente en cualquier página web, por lo que pueden empezar a aparecer entornos de programación completos (IDEs) online y facilitar enormemente realizar cambios a aplicaciones web.
Via WebAppers.
Blogger proveedor de OpenID
Desde ahora, es posible indicar la URL de un blog propio como identificador de OpenID 1.1 desde cualquier sitio que lo solicite. Via Blogger in Draft.
OpenID en Yahoo!
Acaban de venirme tres noticias seguidas del blog de Simon Willison sobre el reciente OpenID de Yahoo!.
- openid.yahoo.com. Guía para humanos de OpenID con Tour. Parece que están interesados en un sello asociado con el equipo para evitar el phishing.
- Ash Patel a través de Willison: Un ID de Yahoo! es una de las cuentas más útiles y reconocibles de internet y con nuestro soporte de OpenID, aún será más potente. Soportar OpenID da a nuestros usuarios la libertad de llevar su ID dentro y fuera de la red de Yahoo!, reduciendo el número de usuarios y claves que necesitan recordar y ofreciendo un solo socio fiable para que gestione tu identidad online.
- Yahoo! anuncia soporte para OpenID. Nota de prensa oficial: "El soporte de Yahoo! triplica el número de cuentas OpenID a 368 millones". Se menciona la identidad dirigida; se habilitará para yahoo.com y para flickr.com. La beta pública se inicia el 30 de Enero.
Sun comprará MySQL
Parece que se ha cerrado una operación de compra de MySQL por parte de Sun, la compañía de Java. Sun To Acquire MySQL. Via Simon Willison.
¿Cual es el tamaño máximo de las URL's?
Limitaciones por navegador y servidor web:
- Internet Explorer: 2083 carácteres
- Firefox: 65536 carácteres
- Safari: 80000 carácteres
- Opera: 190000 carácteres
- Apache: 4000 carácteres
- Microsoft Internet Information Server (IIS): 16384 carácteres
- Perl HTTP::Daemon: 8000 carácteres
El mínimo por tanto serían los 2000 carácteres del IE (cómo no) aunque probablemente con las versiones nuevas se amplie considerablemente. Muy útil a la hora de crear bookmarklets.
Via aNieto2K.
Un OpenID simple para móviles
Ian McKellar ha creado un sistema sencillo para autenticarse en un sitio con OpenID desde un móvil. Ha usado Twitter para permitirle enviar un SMS con un código temporal que servirá como prueba de que se posee el móvil y por tanto la identidad solicitada. Simple y efectivo. Via A simpler mobile OpenID workflow?.
TextboxList
Interesante componente para seleccionar varios elementos de un mismo conjunto desde el teclado y con la ayuda del autocompletado, imitando el iPhone.
Devthought » TextboxList meets Autocompletion
Una cita de Ryan Tomayko
Nunca he oido a nadie de la comunidad REST decir que construir sistemas distribuidos fuese "fácil". [...] Los defensores del WS-* (SOAP) han estado obsesionados históricamente con hacer las cosas fáciles, generalmente para un analista de negocios imaginario que no se acerca al nivel tecnológico que ellos tienen. Los defensores de REST, por otra parte, parecen mucho más interesados en mantener todo el sistema simple y para todos los que lo usen.
- Ryan Tomayko.
Via Simon Willison. Las negritas son mías.
Edsger Dijkstra
Es prácticamente imposible enseñar buena programación a estudiantes que han tenido una exposición previa al BASIC: como programadores potenciales están mutilados más allá de toda esperanza de regeneración.
Edsger Dijkstra

Después del éxito de la prueba mítica de Acid 2 para indicar la compatibilidad de los navegadores con los estándares y con su cada vez mayor adopción, aparece una nueva versión Acid3 (aún no definitiva) de la misma prueba que además tiene tests para Javascript/ECMAScript. Via John Resig
Nueva propuesta: Cross-site XMLHttpRequest
Es bien conocido el problema que aparece al trabajar con Ajax e intentar hacer peticiones a un servidor de un dominio distinto al de la página que solicita la información. Por seguridad no se permiten fácilmente dichas conexiones, obligando a usar proxies u otras técnicas. Esta propuesta del w3C propone la creación de listas de acceso para dar mayor control a los documentos del lado del cliente sobre a qué sitios se permite y a cuales no realizar peticiones desde el documento.
La idea es que desde las mismas cabeceras de la página servida (o sea, desde el propio servidor y sin posibilidad de modificarlo una vez recibido por el cliente) se indiquen los sitios con los que se puede conectar.
Addendum: Firefox 3 ya implementará este mecanismo, además de uno equivalente basado en un archivo XML en el raíz del sitio tal y como explica John Resig.
Mapas de otro mundo
La última versión de la API de Google Maps ya soporta los otros sistemas de Google como Marte y la Luna. Ahora se pueden hacer los típicos mashups con otros planetas.
Javascript Object Hierarchy
Este diagrama explica las relaciones entre objetos, funciones y prototipos de Javascript.
Javascript Object Hierarchy.
$.comet : Plugin jQuery para Comet
Este plugin implementa el protocolo Bayeux (la esencia de Comet) en jQuery. Actualmente soporta handshake (protocolo de inicio de conexión), subscripciones, enlace de callbacks en el sistema de eventos de jQuery basado en nombres de canales.
Seguramente esto despegue al igual que dojox.cometd.
Via Comet Daily y Simon Willison.
Flickr autenticará con OpenID
Cualquier URL de página de usuario de Flickr podrá ser usada como identificador de ese usuario. Siguiendo el estándar OpenID, Flickr pedirá su propia clave para demostrar que quien intenta acceder es el propietario de la página, certificando de esa forma la identidad del usuario.
OpenID es un sistema de identificación digital descentralizado, con el que un usuario puede identificarse en una página web a través de una URL y puede ser verificado por cualquier servidor que soporte el protocolo.
Son buenas noticias por la enorme cantidad de usuarios de Flickr / Yahoo existentes que tendrán un lugar para demostrar su identidad siguiendo el estándar.
Via ReadWriteWeb y Simon Willison.
syntaxhighlighter
syntaxhighlighter es una librería 100% javascript que ayuda a publicar pedazos de código online con facilidad y que tengan muy buena pinta. La he instalado en este mismo blog y se puede ver en posts anteriores. Ejemplo:
Un ajedrez con Inteligencia Artificial en 5 KB
En Javascript claro. Con gráficos. Va a costar años quitar la mala fama del lenguaje debida a las implementaciones de los navegadores. Esto ayuda. p4wn.
Google Caja
Caja es un proyecto de Google que permite ejecutar scripts de terceros sin temer por la seguridad. Caja limpia la parte de Javascript del contenido a publicar eliminando aquellas partes que puedan ser usadas para un escalado de privilegios que permitiera inyectar código malicioso.
Curiosamente, como parte de este proyecto es posible inspeccionar la librería json.js que se usa internamente en Google para convertir una cadena JSON en un objeto Javascript sin usar la función Eval (que permitiría cualquier cosa al contenido a insertar suponiendo una brecha enorme para la seguridad de la aplicación web). Tal y como explican en javascript ant y el propio Douglas Crockford en este artículo.
DataPortability.org - Comparte y mezcla datos usando estándares abiertos
DataPortability.orges un sitio dedicado a la portabilidad de datos. Como usuarios, la identidad, fotos, videos y otras formas de datos personales deberían ser descubribles y compartidos por las herramientas o proveedores que decidamos. Es necesario un estándar como DHCP para la identidad. Un sistema de archivos distribuido para los datos. Esta página listará los estándares y colaboradores que están haciendo que pase.
Los estándares son OpenID (autenticación de usuarios), OAuth (autenticación de APIs), XMPP (mensajería instantánea), RSS (sindicación de contenidos), APML (perfil de intereses), yadis (descubrimiento de servicios de identidad), OPML (suscripciones), hcard (datos personales) y xfn (relaciones).
Lo cierto es que hay en marcha un montón de proyectos muy útiles que necesitan una fuerte cohesión para resultarlo aún más.
EditArea y CodePress
Clausuras javascript para torpes
JavaScript Closures (Clausuras) para torpes
Las clausuras no son mágicas
Esta página explica las clausuras de forma que un programador pueda entenderlas - usando código javascript funcional. No es para gurus ni para programadores funcionales. Las clausuras no son difíciles de comprender una vez que se intuye el concepto clave. De cualquier forma, son imposibles de comprender leyendo sobre ellos en publicaciones académicas o en información orientada a la educación. Este artículo está dirigido a programadores con alguna experiencia en un lenguaje de uso común y que puedan leer la siguiente función javascript:
function decirHola(nombre) {
var texto = 'Hola ' + nombre;
var decirAlerta = function() { alert(texto); }
decirAlerta();
}
Un ejemplo de una clausura
Dos resúmenes de una frase:- Una clausura son las variables locales de una función - mantenidas vivas después de que la función haya retornado, o también
- una clausura es una estructura de pila que no se desasigna cuando la función retorna (como si una estructura de pila se asignara en lugar de permanecer en la pila principal).
function decirHola2(nombre) {
var texto = 'Hola ' + nombre; // local variable
var decirAlerta = function() { alert(texto); }
return decirAlerta;
}
La mayoría de programadores en javascript comprenderán como una referencia a una función es devuelta a una variable en el código anterior. Si no, entonces necesitas entenderlo antes de aprender clausuras. Un programador C podría asociarlo a una función que devuelve un puntero a una función, y que las variables decirAlerta y decir2 fuesen punteros a función. Hay una diferencia crítica entre un puntero en C a una función, y una referencia javascript a una función. En javascript, puedes considerar una variable de referencia a una función como que tiene ambas cosas: un puntero a una función y también un puntero oculto a una clausura. El código anterior tiene una clausura porque la función anónima
function() { alert (text); }
se declara dentro de otra función, decirHola2()
en este ejemplo. En javascript, si usas la palabra clave function
dentro de otra función, estás creando una clausura.
En C, y en la mayoría de los lenguajes de uso común, cuando una función retorna, todas las variables locales dejan de estar accesibles porque la estructura de pila es destruida.
En javascript, si declaras una función dentro de otra función, las variables locales pueden permaneces acceibles después de retornar de la función llamada. Esto se demuestra arriba, porque llamamos a la función say2()
después de haber retornado de decirHola2()
. Fíjate que el código que llamamos referencia a la variable texto
, la cual era una variable local de la función decirHola2()
.
function() { alert(texto); }
Pulsa el botón de arriba para conseguir que javascript muestre el código de la función anónima. Puedes ver que el código hace referencia a la variable
texto
. La función anónima puede referenciar texto
que mantiene el valor 'Rut' porque las variables locales de decirHola2()
se mantienen en la clausura.
La magia es que en javascript una referencia a una función también mantiene una referencia secreta a la clausura en la que fue creada - lo que es similar a cómo los delegados son un puntero a un método más una referencia secreta a un objeto.
Más ejemplos
Por alguna razón las clausuras parecen realmente difíciles de comprender cuando lees sobre ellas, pero cuando ves ejemplos con los que puedes interactuar para ver cómo funcionan, parecen más fáciles. Recomiendo seguir los ejemplos cuidadosamente hasta comprender cómo funcionan. Si empiezas a usar clausuras sin comprender totalmente cómo funcionan, pronto crearás errores muy extraños y difíciles de depurar.Ejemplo 3
Este ejemplo muestra que las variables locales no se copian (se mantienen por referencia). Es cómo mantener una estructura de pila en memoria cuando la función retorna.
function decir667() {
// Variable local que termina en la clausura
var num = 666;
var decirAlerta = function() { alert(num); }
num++;
return decirAlerta;
}
Ejemplo 4
Las tres funciones globales tienen una referencia común a la misma clausura porque las tres están declaradas dentro de una misma llamada aestableceUnasGlobales()
.
function estableceUnasGlobales() {
// variable global que termina dentro de la clausura
var num = 666;
// almacena algunas referencias a funciones como variables globales
gAlertaNumero = function() { alert(num); }
gIncrementaNumero = function() { num++; }
gPonNumero = function(x) { num = x; }
}
estableceUnasGlobales()
donde las tres funciones se han definido.
Ten en cuenta que en el ejemplo anterior, si pulsas estableceUnasGlobales()
de nuevo, entonces una nueva clausura (estructura de pila) se creará. Las viejas variables gAlertaNumero
, gIncrementaNumero
, gPonNumero
son sobreescritas con nuevas> funciones que tienen una nueva clausura. (En javascript, cuando declaras una función dentro de otra, la(s) funcion(es) interior(es) es/son recreadas de nuevo cada vez la función externa es llamada).
Ejemplo 5
Este es una verdadera fuente de fallos para mucha gente, así que necesitas entenderlo. Ten mucho cuidado si estás definiendo una función dentro de un bucle: las variables locales de la clausura podrían no actuar como podrías pensar en principio.
function construyeLista(lista) {
var resultado = [];
for (var i = 0; i < lista.length; i++) {
var item = 'item' + lista[i];
resultado.push( function() {alert(item + ' ' + lista[i])} );
}
return resultado;
}
function testLista() {
var fnlista = construyeLista([1,2,3]);
// uso j sólo para prevenir confusión con i
for (var j = 0; j < fnlista.length; j++) {
fnlista[j]();
}
}
La línea
resultado.push( function() {alert(item + ' ' + lista[i])}
añade una referencia a una función anónima tres veces al array resultado. Si no estas familiarizado con las funciones anónimas, considéralas como:
puntero = function() { alert(item + ' ' + lista[i]) };
resultado.push(puntero);
Ten en cuenta que cuando ejecutas el ejemplo, aparece la alerta "item3 undefined" tres veces. Eso es porque, igual que en los ejemplos previos, hay sólo una clausura para las variables locales de construirLista
. Cuando las funciones anónimas son llamadas en la línea fnlista[j]();
todas usan la misma clausura, y usan el valor actual de i
e item
dentro de esa clausura (donde i
tiene un valor de 3
porque el bucle se ha completado, e item
tiene el valor de 'item3'
).
Ejemplo 6
Este ejemplo muestra que la clausura contiene cualquier variable local que fuese definida en la función externa antes de retornar. Ten en cuenta que la variablealicia
se declara realmente después de la función anónima. La función anónima es declarada primero: y cuando esa función es llamada, puede acceder a la variable alicia
porque alicia
está en la clausura.
También decirAlicia()();
directamente llama a la referencia de la función devuelta de decirAlicia()
- que es justo lo mismo que fue hecho previamente, pero sin la variable temporal.
function decirAlicia() {
var decirAlerta = function() { alert(alicia); }
// variable local que termina estando dentro de la clausura
var alicia = 'Hola Alicia';
return decirAlerta;
}
Cuidado: ten en cuenta también que la variable
decirAlerta
está dentro de la clausura, y que podría ser accedida por cualquier otra función declarada dentro de decirAlicia()
o podría ser accedido recursivamente desde la función de dentro.
Ejemplo 7
Este ejemplo final muestra que cada llamada crea una clausura separada para las variables locales. No hay una única clausura para la declaración de función. Hay una clausura para cada llamada a una función.
function nuevaClausura(algunNum, algunaRef) {
// variables locales que terminan dentro de la clausura
var num = algunNum;
var unArray = [1,2,3];
var ref = algunaRef;
return function(x) {
num += x;
unArray.push(num);
alert('num: ' + num +
'\nunArray ' + unArray.toString() +
'\nref.algunaVar ' + ref.algunaVar);
}
}
Resumen
Si todo parece completamente liado, lo mejor es jugar con los ejemplos. Leer una explicación es mucho más difícil que entender los ejemplos. Mis explicaciones de las clausuras y estructuras de pila no son técnicamente correctas - son simplificaciones burdas dirigidas a ayudar a la comprensión. Una vez se intuye la idea básica, puedes pararte en los detalles después. Puntos finales:- Cuando se use
function
dentro de otra función, se usa una clausura. - Cuando se use
eval()
dentro de una función, se usa una clausura. El texto que evalúas puede referenciar variables locales de una función, y dentro del eval puedes incluso crear nuevas variables locales usandoeval('var foo= ...
- Cuando uses
Function()
dentro de una función, no se crea una clausura. (La nueva función no puede referenciar variables locales de la función llamandoFunction()
). - Una clausura en javascript es como mantener copia de todas las variables locales, justo como estaban cuando la función retornó.
- Es mejor pensar que una clausura se crea siempre en el momento de la entrada a la función, y que las variables locales se añaden a esa clausura.
- Un nuevo conjunto de variables locales se mantiene cada vez que una función con una clausura es llamada (Dado que las funciones contienen una declaración de función en su interior, una referencia a esa función interior es retornada o bien se mantiene una referencia externa de alguna manera).
- Dos funciones podrían parecer que tienen el mismo código pero podrían tener un comportamiento totalmente distinto debido a su clausura 'oculta'. No creo que el código javascript pueda realmente averiguar si una referencia a función tiene una clausura o no.
- Si estás intentando hacer cualquier modificación de código fuente ( por ejemplo:
miFuncion = Function( miFuncion.toString().replace(/Hola/,'Buenas'));
), no funcionará si miFuncion es una clausura (Desde luego, nunca nunca pensarías en hacer sustituciones de cadenas sobre código fuente, pero ... ). - Es posible obtener declaraciones de funciones dentro de declaraciones de funciones dentro de funciones - y puedes obtener clausuras a más de un nivel.
- Creo que normalmente una clausura es la definición usada para ambos, la función y las variables que son capturadas. Ten en cuenta que no uso esa definición en este artículo.
- Sospecho que las clausuras de javascript difieren de las que se encuentran normalmente en los lenguajes funcionales.
Enlaces
- TrimBreakpoint hace un uso rebuscado de las clausuras para dejarte inspeccionar las variables locales de una función desde una ventana emergente de breakpoint (punto de ruptura de la ejecución).
- Douglas Crockford ha simulado atributos y métodos privados para objetos usando clausuras.
- Una gran explicación de cómo las clausuras pueden causar fugas de memoria en IE si no tienes cuidado. Al menos con las versiones anteriores a la 7.