Los 4 Jinetes del Apocalipsis

No os preocupéis, que aunque me estoy pasando al lado oscuro aún no he perdido la cabeza, no quiero hablar de “caballo blanco”,”caballo rojo”,”caballo negro” y “caballo bayo”. En esta ocasión voy a hablar de otros 4 jinetes que pueden hacer de nuestro código una apocalipsis. Me refiero concretamente a estos 4 “this”,”call”, ”apply” y “bind” de quien?

De quien va a ser, de mis últimas andadas por “Javascript”. Bueno vamos al grano:).

this: Sobre este hay ríos de tinta, pero voy a intentar explicarlo desde una lógica. Cuando nosotros definimos una función tal como esta.

console.log(window.name);
function foo(name) {
this.name = name;
}
console.log(window.name);

Y la invocamos como foo(‘window’). Lo que realmente estamos haciendo es llamar a un método que hemos definido en el objeto window (ámbito global) y agregando a  este sino lo tiene una propiedad con nombre “name”, no es el caso puesto que window ya posee una propiedad llamada “name”.
 
En realidad tiene todo el sentido del mundo foo pertenece a window y por tanto this es window. para comprobarlo podéis ejecutar
 
“foo” in window y devuelve true.
 
¿Cuándo this es foo ? pues cuando hacemos lo siguiente:
 
window.name = "window";
function foo(name) {
this.name = name;
}
var objeto = new foo("mi nombre");
console.log(window.name);
console.log(objeto.name);
 
La salida en este caso es “window” para window.name y “mi nombre” para “objeto.name”. Lo que hemos hecho no es invocar un método sino crear un objeto del tipo foo y por tanto this es el y no el ámbito global.
 
Vamos ahora a definir un objeto y vemos que su comportamiento es exactamente el mismo.
 
objeto = {
name: "",
surname: "",
fullname: function () {
console.log(this.name + " " + this.surname);
}
}
objeto.name = "Pedro";
objeto.surname = "Hurtado";
objeto.fullname();
 
Ya podemos decir que “this” se comporta de la forma esperada “this representa el objeto al que pertenece nuestro método o propiedad”  no cambia respecto a lo que estamos acostumbrados.
 
Pero claro en este fantástico lenguaje “de verdad”, siempre tiene que haber una excepción y la excepción es “this entra en el limbo”. 
 
Vamos con un ejemplo.
 
window.name = "window";
function foo(name,surname){
this.name = name;
this.surname = surname;
this.fullname = function () {
function writeFullName() {
console.log(this.name + " " + this.surname);
}
writeFullName();
}
}

var objeto = new foo("Pedro", "Hurtado");
objeto.fullname();
 
En este caso alguno puede pensar que la salida por consola será “Pedro Hurtado”, pues no this se fue al limbo y la salida es “window undefined”. Y si antes dijimos que “this representa al objeto al que pertenece el método o propiedad”
 
¿A quien pertenece WriteFullName?.
 
Mis ojos me dicen que a nadie es algo raro, esta en el limbo:). Bueno señores ese limbo no es otro que el objeto global “window”.
 
Y alguien puede decir menuda ….. No por favor!!!. Vienen a salvarnos los otros tres jinetes.
 
call: Realmente es un método del objeto “Function” si “F” con mayúscula y nos permite invocar a una función pasando en el primer parámetro el ámbito es decir this y en el segundo parámetro una lista de los posibles parámetros separados por comas, yo en este caso no lo estoy utilizando, una de las bondades o maldades del dinamismo .
 
 
window.name = "window";
function foo(name,surname){
this.name = name;
this.surname = surname;
this.fullname = function () {
function writeFullName() {
console.log(this.name + " " + this.surname);
}
writeFullName.call(this);
}
}
var objeto = new foo("Pedro", "Hurtado");
objeto.fullname();
Ahora si que el resultado es el esperado, por consola la salida será “Pedro Hurtado”.
 
apply: De este poco que decir una vez explicado que hace call. La única diferencia es que el segundo parámetro se pasa como una array. La verdad que no se cual fue primero si call o apply pero realmente son el mismo perro con distinto collar:).
 
bind: Tratemos al último jinete este a diferencia call y apply lo que hace es establecer el ámbito y si se quiere los parámetros pero no invoca a la función. Es decir devuelve un objeto que después podemos invocar.
 
Como podemos observar los metodos “call”, “apply” y “bind” tiene un comportamiento parecido y lo que vienen es a suplir  la carencia real de javascript de no tener bien resuelto el funcionamiento de this.
 
Con lo cual tenemos que tener mucho cuidado con el uso de this en los callback que tan de moda se han puesto. Si por ejemplo observáis código WinJs se puede ver que casi siempre que se ejecuta algún Promise y queremos tratar con this nos encontramos con bind.
 
Lo que realmente hace falta desde mi punto de vista es ya de una vez, alguna palabra reservada como “class”  y su funcionamiento lógicamente implementado. Si las fuentes no me fallan creo que estamos en el camino http://wiki.ecmascript.org/doku.php?id=harmony:classes, pero claro seguro que protected override o alguna otra la dejan para la versión no harmony sino para la versión ecma-apocalypse.
 
Conclusiones.
 
De lo más sencillo, evita el uso de this en javascript. No solo te puedes llevar sorpresas sino que además vas a definir variables innecesarias en el ámbito global, si después de esto sigues empeñado en el uso de this, acuérdate de usar si lo necesitas los otros tres jinetes.

Soy asincrono despues de 0 milisegundos

Posiblemente alguno  puede seguir pensando que escribir un Promise es hacer su código Javascript asíncrono. Bueno pues si piensas eso ya te digo yo que no.

Promise no es más que un mecanismo para hacer nuestro código más legible y de esa forma evitar los tediosos callback que hasta el momento hemos utilizado.

Bueno como siempre vamos a empezar con un ejemplo para demostrar que Promise no es asíncrono.

function promise() {
return new WinJS.Promise(function (complete, error, progress) {
try {
var i = 0;
for (i = 0; i < 10; i++) {
progress(i);
}
complete(i);
}
catch (ex) {
error(ex);
}
});
}
function runPromise() {
var result = promise().then(
function (data) {
console.log(data);
},
function (progress) {
console.log(progress);
},
function (error) {
console.log(error);
});

}
runPromise();
Si analizamos este código la respuesta inmediata sería, la salida por consola nos mostrará  la siguiente secuencia 0,1,2,3,4,5,6,7,8,9 y por último 10. La respuesta es por consola solamente vamos a ver “10”, es decir la ejecución de complete, pero nunca progress.
 
Ante esto la pregunta  ¿Si progress se ejecuta y no es “undefined”, porque no escribe en la consola el valor de i?. Pues sencillo o creo que más bien complicado:).
 
Cuando ejecutamos el constructor de una Promise pasan varias cosas.
 
1. Se pasa al contructor una función anónima que recibe tres parámetros “complete,error,progress” y se ejecuta.
 
2. Ninguno de los tres parametros apunta en realidad a las funciones que he pasado como parametros  a la función then. Puesto que aún no se ha ejecutado, sino a “complete,error,progress” de “PromiseStateMachine” una clase que se crea en base.js de la que deriva “Promise”.
 
3. ¿Y por qué se ejecuta “complete” y no “progress”? Pues por eso por que Javascript es “single-threaded”. Realmente la línea de código siguiente “complete(i)” no hace lo que creemos , sino asignar un valor “10”  al objeto Promise que hemos creado.
 
4. Bueno ¿Y entonces porque ejecuta lo siguiente?
 
function (data) {
console.log(data);
},
 
Porque al ejecutar “then” después de nuestra función anónima nuestra Promise ha realizado internamente lo suficiente como para que “then” sea un objeto del tipo “CompletePromise” y llama a la función “then” de este, ¿queréis ver  el código? 🙂
 
try {
// If the value returned from the completion handler is the same as the value
// provided to the completion handler then there is no need for a new promise.
//
var newValue = onComplete ? onComplete(this._value) : this._value;
return newValue === this._value ? this : new CompletePromise(newValue);
} catch (ex) {
return new ExceptionPromise(ex);
}

En la primera linea se ve claramente que se llama a “onComplete”,  función que escribe en la consola nuestro famoso “10”. De lo cual podemos deducir que primero se ejecuta nuestro bucle y después “then”, sino os convence podéis cambiar el valor 10 por 100000000 y ya os digo yo que os vais a esperar un poquito o más bien mucho:).
 
Bueno después de este tedioso rollo, quizá alguien se pregunte para que quiero utilizar Promise, bueno mi conclusión es sencilla como dije nos ayuda a estructurar nuestro código de mejor forma, cosa que no implica que mi código sea asíncrono. Queda claro no:).
 
Queréis el mismo código asíncrono, entre comillas:), bueno pues otra función anónima que ejecute nuestro bucle pero con “setTimeout”.
 
function promise() {
return new WinJS.Promise(function (complete, error, progress) {
var id;
id = setTimeout(function () {
try{
for (var i = 0; i < 10; i++) {
progress(i);
}
complete(i);
}
catch (ex) {
error(ex);
}
finally {
if (id) {
clearTimeout(id);
}
}
}, 0);
});
}
function runPromise() {
promise().then(
function (data) { console.log(data); },
function (progress) { console.log(progress); },
function (error) { console.log(error); }
);
}
runPromise();

Y a estás alturas alguien puede pensar y porque el titulo de este post, pues porque por casualidades de la vida ayer me encontré con esta otra entrada que es digna de leer y yo paso un 0 a setTiemout:).

setImediate Api

Me tome la molestia de escribir este script y probarlo en Chrome,FireFox e IE9 y la verdad que me sorprendió, bastante que Chrome sea el más lento en ejecutar callback por segundosSonrisa

var i = 0,
id,
endDate,
startDate = new Date().getTime(),
ckeckEnd = function () {
endDate = new Date().getTime();
var result = (endDate - startDate)
if (result >= 1000) {
if (id) clearInterval(id)
console.log(result + " " + i);

}
else {
i++;
}

};
id = setInterval(function () {
ckeckEnd();
}, 1);

Conclusion:

Que todo esto es un mundo desconocido para los que venimos de c# y que realmente explorarlo es toda una satisfacción, aunque podemos decir que Javascript tiene mucho, pero mucho que mejorarSonrisa

 

Ocultar o esconder no es prohibir

Si me pongo a pensar y me traslado al pasado, siempre hable mal de Javascript. Últimamente he cambiado mi actitud pero con peros, es decir es un lenguaje que tiene que mejorar y no poco:).

Revisando WinJS, de esa forma que me gusta a mí. No haciendo el típico ejemplo “Hola Mundo”, sino adentrándome en las profundidades de “base.js” me encuentro con lo siguiente:

function initializeProperties(target, members) {
var keys = Object.keys(members);
var properties;
var i, len;
for (i = 0, len = keys.length; i < len; i++) {
var key = keys[i];
var enumerable = key.charCodeAt(0) !== /*_*/95;
var member = members[key];
if (member && typeof member === 'object') {
if (member.value !== undefined || typeof member.get === 'function' || typeof member.set === 'function') {
if (member.enumerable === undefined) {
member.enumerable = enumerable;
}
properties = properties || {};
properties[key] = member;
continue;
}
}
if (!enumerable) {
properties = properties || {};
properties[key] = { value: member, enumerable: enumerable, configurable: true, writable: true }
continue;
}
target[key] = member;
}
if (properties) {
Object.defineProperties(target, properties);
}
}
 

La verdad que tampoco me adentre mucho, puesto que esto te lo encuentras entre las líneas 15 y 46 de base.js.

Lo que más me llamo la atención fue concretamente esta línea

“var enumerable = key.charCodeAt(0)!== /*_*/ 95;

En realidad eso lo que hace es comprobar, como bien podéis ver si el primer carácter de una propiedad empieza por “_” y marcar enumerable como false.

¿Que es enumerable?

Pues sencillo uno de los parametros del objeto que pasamos en el tercer de los parametros a Object.defineProperty. Seguro que alguno se estará preguntado si esto significa que esa propiedad es privada por aquello de “_” , bueno eso no es así. Realmente lo que hace es ocultar esta propiedad a los siguientes métodos, entre otros:

1. Object.Keys(objecto);

2. for (prop in objecto)

Por contra  esa propiedad será accesible si accedemos a ella de la siguiente forma:

1. objeto._propiedad.

2. objecto[“_propiedad”]

3. “_propiedad” in objeto devuelve true;

Os paso el siguiente script por si alguien quiere conprobarlo.

var objeto = {};
Object.defineProperty(objeto, "_propiedad", { value: 10, enumerable: false, writable: true, configurable: true });
for (var propiedad in objeto) {
console.log(propiedad);
}
objeto["_propiedad"] = 20;
console.log(objeto["_propiedad"]);
console.log(objeto._propiedad);
console.log("_propiedad" in objeto);

Que hace por nosotros Visual Studio a nivel de Intellisense. Pues sencillo ocultar cualquier propiedad de un objeto javascript cuyo nombre empiece por “_”. Eso es bueno, pues para quien lo quiera quizá sí, para mí ya os digo que no, puesto que en el fondo esa propiedad es tan publica como cualquier otra.

De eso es fácil deducir  que cualquier objeto creado en WinJS con los métodos

WinJS.Namespace y WinJS.Class expone todas sus propiedades como públicas.

La pregunta a esto es sencilla ¿a quien le gusta esto?.

Como referencias os paso los siguientes link.

http://msdn.microsoft.com/es-es/library/kb6te8d3(v=vs.94).aspx

http://msdn.microsoft.com/es-es/library/hh965578(v=vs.94).aspx

http://kangax.github.com/es5-compat-table/#showold

Veis como Ocultar no es Prohibir Sonrisa.