RSS Feed

Patrones de Invocación de Funciones: this

5

enero 23, 2012 by - @pjnovas

Cada vez que llamamos a una función en javascript se crea un nuevo contexto, en el cual tenemos this y arguments, el último lo pueden ver mejor explicado en este post. El this se va a inicializar de distintas formas dependiendo de como invoquemos a la función.

Hay 4 patrones para invocar una función:

  • como Método
  • como Función
  • como Constructor
  • y con Apply

Patrón de invocación como Método

Cuando una función es guardada como una propiedad de un objeto, lo llamamos método. En este caso this es inicializado con el objeto al que pertenece la función.

var obj = {
    valor = 0,
    incrementar: function(incremento){
       this.valor += incremento;
    }
};

obj.incrementar(2);
console.log(obj.valor); // 2

Patrón de invocación como Función

Cuando una función no está dentro de un objeto es invocada como función, y this es inicializado con el Objeto Global. Esto es un problema, ya que cuando llamamos a una función dentro de otra, this sigue referenciando al Objeto Global y si queremos acceder al this de la función padre tenemos que almacenarlo en una variable primero:

var obj = {
    valor = 0,
    incrementar: function(incremento){ // es invocado como método
       var that = this;

       function otraFuncion(unValor){ //es invocado como función
           //en esta función this referencia al Objeto Global
           that.valor += unValor;
       }

       otraFuncion(incremento);
    }
};

obj.incrementar(2);
console.log(obj.valor); // 2

Patrón de invocación como Constructor

Javascript es un lenguaje de herencia prototipada, lo que significa que un objeto puede heredar directamente propiedades de otro objeto y como su prototipado no es muy convincente, javascript ofrece una sintaxis estilo creación de objetos como en los lenguajes clasicos de POO (Programación Orientada a Objetos).
Dicho esto, cuando invocamos una función con new se creará un objeto con una referencia al valor de su miembro de función prototipada (también llamado constructor) y this tendrá una referencia a este nuevo objeto.

var Persona = function(){ // nuestro "constructor"
    this.nombre = 'José';
}
Persona.prototype.mostrarNombre = function(){
    console.log(this.nombre); //con this accedemos al constructor
}

var p = new Persona();
p.mostrarNombre(); //imprime 'José'

como vimos antes, si invocamos la función Persona() sin el new, this se inicializa distinto y nuestra clase se va a comportar de forma muy extraña, es por eso que como convención llamamos a las clases con la primer letra en mayúscula.

Patrón de invocación con Apply

La función apply nos deja construir un arreglo de argumentos para usar al invocar una función y también nos deja elegir el valor que tendrá this.
apply recibe 2 parametros, el primero es el valor para this y el segundo es un arreglo de parámetros.

Usando el ejemplo anterior de prototipado, vamos a cambiar el this utilizando el apply

var Persona = function(){ // nuestro "constructor"
    this.nombre = 'José';
}
Persona.prototype.mostrarNombre = function(){
    console.log(this.nombre); //con this accedemos al constructor
}

//con apply cambiamos el this referenciado al objeto persona por otroObjeto
var otroObjeto = {
    nombre: 'Pepe'
};

var p = new Persona();
p.mostrarNombre(); //imprime 'José'
p.mostrarNombre.apply(otroObjeto); // imprime 'Pepe'

Fuente: JavaScript: The Good Parts – Douglas Crockford


  • Maxi Nicolas Nievas

    Esto me suena a The good parts de la coleccion O’Reilly, pero como no soy bueno con ingles, me vino barbaro esto.
    Muy buena pagina por cierto.

    Saludos !

    Maxi Nievas

  • pjnovas

    Gracias Maxi!, y si fue tomado como referencia del libro: Javascript: The Good Parts de Douglas Crockford, el libro está especificado en la “Fuente” al final de post.

    Saludos!

  • arturo

    Otro muy bueno es el siguiente;

    var Persona = function (){
    this.nombre=””;
    return{
    set: function(a){
    this.nombre = a
    } // end set
    } // end return
    }// end persona

    memo = new Persona();
    memo.set(“juan”);

    • pjnovas

      Arturo, el tema que tenes con esa forma es que podes acceder a la propiedad “nombre” de Persona sin necesidad del set:
      memo.nombre = “juan”;

      En el momento que invocas a la función Persona con un “new” estás utilizando el patrón de invocación por Constructor, por lo que todo lo que hayas declarado con “this” puede ser accedido desde “afuera”.

      Podrías hacer algo así para cerrar acceso:


      var Persona = function(){
      var nombre = "";
      this.set = function(a){
      nombre = a;
      };
      };
      var memo = new Persona();
      memo.set("juan");

      Saludos!

    • Alex

      Hola soy nuevo en Javascript amm.. independiente del tema del this (que por cierto esta muy bueno)
      he estado viendo ultimamente mucho ese return
      y no entiendo el porque hacer un return y definir un metodo dentro de el, cuando se podria definir el metodo sin hacer el return :c ?!

      la verdad estoy muy colgado, por eso aprovecho tu comentario para ver si alguien me ayuda e.e !