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.

2 comentarios en “Los 4 Jinetes del Apocalipsis”

  1. Veo que te lo estás pasando muy bien con js 🙂

    Una alternativa muy usada en Javascript para evitar el problema de perder la referencia a this durante la declaración de un objeto, es asignarlo a una variable (generalmente llamada self) y aprovechar el cierre lambda sobre esa variable para no tener que referenciar el this:


    function foo(name,surname){
    var self = this;
    self.name = name;
    self.surname = surname;
    self.fullname = function () {
    function writeFullName() {
    console.log(self.name + " " + self.surname);
    }
    writeFullName();
    }
    }

  2. Hola Juanma,

    La verdad que si que lo estoy pasando bien:). Esta claro que trucos hay mil. El primero de ellos no declarar writeFullName que no tiene ningún sentido o el que tu comentas. Pero el mensaje de esta serie post es sencillo un lenguaje pensado para escribir 4 script que queremos de el lo que no es posible y evoluciona de forma lenta, sin ir mas lejos bind no funciona en determinadas versiones de exploradores.

    La realidad que esto debería de cambiar:). Pero lo veo como una utopía.

    Saludos y gracias!!!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *