this en JavaScript: cómo cambia según el contexto de llamada

this en JavaScript no apunta a la función que lo contiene ni al objeto donde se define: apunta al contexto de invocación, es decir, a cómo se llama la función. Esta regla simple explica todos los comportamientos de this y todos los bugs que genera cuando no se tiene en cuenta.

this en el contexto global

En el ámbito global, fuera de cualquier función, this apunta al objeto global. En navegadores es window; en Node.js es global (o globalThis en versiones modernas):

// En el navegador
console.log(this === window);  // true

// En modo estricto en el global, this sigue siendo el global
'use strict';
console.log(this === window);  // true (en global)

// En Node.js
console.log(this === global);  // false en módulos ES
console.log(this === globalThis);  // true en cualquier entorno

this en métodos de objeto

Cuando llamas a una función como método de un objeto (con la notación objeto.metodo()), this apunta al objeto que hay a la izquierda del punto:

const usuario = {
  nombre: 'Ana',
  saludar() {
    console.log('Hola, soy ' + this.nombre);
  }
};

usuario.saludar();  // "Hola, soy Ana"

// Si extraes el método, pierdes el contexto:
const fn = usuario.saludar;
fn();  // "Hola, soy undefined" (this = window/global)

this en funciones normales

Una función regular llamada directamente (no como método) tiene this igual al objeto global en modo no estricto, y undefined en modo estricto:

function mostrarThis() {
  console.log(this);
}

mostrarThis();  // window (no estricto) / undefined (estricto)

'use strict';
function mostrarThisEstricto() {
  console.log(this);  // undefined
}
mostrarThisEstricto();

El bug clásico: perder this en callbacks

Este es el problema más frecuente con this. Al pasar un método como callback, se pierde el contexto del objeto:

const temporizador = {
  segundos: 0,
  iniciar() {
    // Bug: this dentro del callback no es temporizador
    setInterval(function() {
      this.segundos++;  // Error: this es window/undefined
      console.log(this.segundos);
    }, 1000);
  }
};

// Solución 1: guardar referencia a this
const temporizador2 = {
  segundos: 0,
  iniciar() {
    const self = this;
    setInterval(function() {
      self.segundos++;
      console.log(self.segundos);
    }, 1000);
  }
};

// Solución 2: arrow function (hereda this del scope externo)
const temporizador3 = {
  segundos: 0,
  iniciar() {
    setInterval(() => {
      this.segundos++;  // this es temporizador3
      console.log(this.segundos);
    }, 1000);
  }
};

this con new

Cuando usas new con una función constructora o clase, this apunta al nuevo objeto que se está creando:

function Producto(nombre, precio) {
  this.nombre = nombre;
  this.precio = precio;
  this.conIva = function() {
    return this.precio * 1.21;
  };
}

const libro = new Producto('JS Moderno', 30);
console.log(libro.nombre);      // 'JS Moderno'
console.log(libro.conIva());    // 36.3

Arrow functions y this

Las funciones flecha no tienen su propio this: heredan el this del scope donde se definen (no donde se llaman). Esto las hace ideales para callbacks, pero las descarta como métodos de objeto o constructores:

const objeto = {
  valor: 42,
  // MAL: arrow function como método, this no es objeto
  obtenerMal: () => this.valor,  // undefined

  // BIEN: function normal
  obtenerBien: function() { return this.valor; }  // 42
};

console.log(objeto.obtenerMal());   // undefined
console.log(objeto.obtenerBien());  // 42

La forma de determinar this en cualquier momento: mira a la izquierda del punto cuando se llama la función. Si no hay punto, es el global o undefined en modo estricto. Si hay new, es el nuevo objeto. Si es una arrow function, sube al scope donde fue definida.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP