preloader

Tipo de Referencia en JavaScript

Característica avanzada del lenguaje

Este artículo cubre un tema avanzado que ayuda a entender ciertos casos límite del comportamiento de JavaScript.

Esto no es crucial para la mayoría de los desarrolladores, pero si quieres saber cómo funcionan las cosas a nivel interno, sigue leyendo.

Pérdida del valor de this en llamadas dinámicas de métodos

Consideremos el siguiente ejemplo:

				
					let user = {
  name: "John",
  hi() { alert(this.name); },
  bye() { alert("Bye"); }
};

user.hi(); // Funciona

// Ahora llamemos a user.hi o user.bye dependiendo del nombre ingresado
(user.name == "John" ? user.hi : user.bye)(); // ¡Error!

				
			

En la última línea, un operador condicional decide entre user.hi o user.bye. En este caso, el resultado es user.hi.

Sin embargo, el método es llamado con paréntesis (), pero esto no funciona correctamente.

Como puedes observar, la llamada resulta en un error porque el valor de this dentro de la función se convierte en undefined.

Esto funciona correctamente (objeto, punto, método):

				
					user.hi();

				
			

Esto no funciona (método evaluado dinámicamente):

				
					(user.name == "John" ? user.hi : user.bye)(); // ¡Error!

				
			

¿Por qué sucede esto? Para entenderlo, veamos cómo funciona la llamada obj.method() internamente.

Explicación del Tipo de Referencia

Analizando más de cerca, podemos notar que hay dos operaciones en la declaración obj.method():

  1. El punto . recupera la propiedad obj.method.
  2. Los paréntesis () ejecutan esa propiedad.

Entonces, ¿cómo se transfiere la información de this de la primera parte a la segunda?

Si dividimos estas operaciones en líneas separadas, this se perderá sin duda:

				
					let user = {
  name: "John",
  hi() { alert(this.name); }
};

// Separamos la obtención de la propiedad y la llamada al método en dos líneas
let hi = user.hi;
hi(); // Error porque this es indefinido

				
			

Aquí, hi = user.hi asigna la función a una variable, y la llamada subsecuente es completamente independiente, por lo que this no se mantiene.

Para que la llamada user.hi() funcione, JavaScript utiliza un truco: el punto . no devuelve una función, sino un valor especial del Tipo de Referencia.

El Tipo de Referencia es un «tipo de especificación». No podemos usarlo directamente, pero el lenguaje lo emplea internamente.

El valor del Tipo de Referencia es una combinación de tres elementos (base, name, strict), donde:

  • base es el objeto.
  • name es el nombre de la propiedad.
  • strict es verdadero si use strict está en efecto.

El resultado de acceder a la propiedad user.hi no es una función, sino un valor del Tipo de Referencia. Para user.hi en modo estricto, esto es:

				
					// Valor del Tipo de Referencia
(user, "hi", true)

				
			

Cuando se llaman los paréntesis () sobre el tipo de referencia, reciben toda la información sobre el objeto y su método, y pueden establecer el valor de this correctamente (en este caso, user).

El Tipo de Referencia es un tipo interno de «intermediario» cuyo propósito es pasar información desde el punto . hacia los paréntesis () de la llamada.

Cualquier otra operación, como la asignación hi = user.hi, descarta el tipo de referencia por completo, toma el valor de user.hi (una función) y lo pasa. De esta manera, cualquier operación “pierde” this.

Por lo tanto, el valor de this solo se pasa correctamente si la función se llama directamente usando la sintaxis de punto obj.method() o corchetes obj['method']() (ambos funcionan de la misma manera). Existen varias formas de resolver este problema, como func.bind().

Resumen

El Tipo de Referencia es un tipo interno del lenguaje.

Leer una propiedad usando el punto . en obj.method() no devuelve exactamente el valor de la propiedad, sino un valor especial del «tipo de referencia» que almacena tanto el valor de la propiedad como el objeto del que se tomó.

Esto se hace para que la llamada () al siguiente método pueda obtener el objeto y establecer this correctamente.

Para todas las demás operaciones, el tipo de referencia se convierte automáticamente en el valor de la propiedad (una función en nuestro caso).

Toda esta mecánica está oculta a nuestros ojos y solo importa en casos sutiles, como cuando un método se obtiene dinámicamente del objeto usando una expresión.

Related Post

Deja una respuesta

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