preloader

Constructor, operador «new»

Constructor, operador «new»

La forma habitual {…} nos permite generar un objeto. Sin embargo, en muchas ocasiones necesitamos crear múltiples objetos similares, como varios usuarios o elementos de menú.

Para esto, podemos utilizar funciones constructoras junto con el operador «new».

Función constructora

Una función constructora es esencialmente una función estándar, aunque existe una convención:

  • Deben nombrarse con la primera letra en mayúscula.
  • Deben ser invocadas exclusivamente con el operador «new».

Por ejemplo:

				
					function User(name) {
  this.name = name;
  this.isAdmin = false;
}

let user = new User("Jack");

alert(user.name); // Jack
alert(user.isAdmin); // false

				
			

Cuando se utiliza new User(…), se realiza lo siguiente:

  1. Se crea un nuevo objeto vacío y se asigna a this.
  2. Se ejecuta el cuerpo de la función. Usualmente, esto implica modificar this y añadir nuevas propiedades.
  3. Se devuelve el valor de this.

En esencia, new User(…) realiza una operación similar a:

Objetos Entrelazados

				
					function User(name) {
  // this = {};  (implícito)

  // Se agregan propiedades a this
  this.name = name;
  this.isAdmin = false;

  // return this;  (implícito)
}

				
			

Así, let user = new User(«Jack») produce el mismo resultado que:

				
					let user = {
  name: "Jack",
  isAdmin: false
};

				
			

Esto facilita la creación repetida de objetos similares, más conciso que usar literales de objeto repetidamente y también más legible.

Este es el propósito principal de los constructores: implementar código reutilizable para la creación de objetos.

Constructor inmediatamente invocado

En situaciones donde necesitamos un único objeto complejo y no planeamos reutilizar el constructor, podemos encapsular su creación de la siguiente manera:

				
					// Crea una función y la llama inmediatamente con new
let user = new function() {
  this.name = "John";
  this.isAdmin = false;

  // Otro código para la creación del usuario
  // Lógica compleja, declaraciones de variables locales, etc.
};

				
			

Este tipo de constructor no puede ser llamado nuevamente, ya que no se guarda en ninguna variable. Se crea y se invoca al mismo tiempo para encapsular la lógica de construcción del objeto individual.

Constructor en modo test: new.target

Temas avanzados

La sintaxis de esta sección es raramente utilizada y puede omitirse a menos que se desee un conocimiento completo.

Dentro de una función, podemos verificar si ha sido invocada con o sin new utilizando una propiedad especial: new.target.

En llamadas normales, devuelve undefined, pero en llamadas con new devuelve la función constructora:

				
					function User() {
  alert(new.target);
}

// Sin "new":
User(); // undefined

// Con "new":
new User(); // function User { ... }

				
			

Esto puede ser utilizado dentro de la función para determinar si fue llamada con new, en modo constructor, o sin él, en modo regular.

Redirigiendo llamadas

También podemos redirigir ambas formas de llamada, con y sin new, para realizar lo mismo:

				
					function User(name) {
  if (!new.target) { // Si se llama sin new
    return new User(name); // Agrega new por nosotros
  }

  this.name = name;
}

let john = User("John"); // Redirige la llamada a new User
alert(john.name); // John

				
			

Este enfoque a veces se usa en bibliotecas para proporcionar una sintaxis más flexible, permitiendo a los usuarios llamar la función con o sin new y que aún funcione correctamente.

Return desde constructores

Normalmente, los constructores no tienen una sentencia return. Su función es escribir todo lo necesario en this, que luego se convierte automáticamente en el resultado.

Sin embargo, si hay una sentencia return, la regla es simple:

  • Si return devuelve un objeto, ese objeto se devuelve en lugar de this.
  • Si return devuelve un tipo de dato primitivo, es ignorado.

Por ejemplo:

				
					function BigUser() {
  this.name = "John";

  return { name: "Godzilla" };  // <-- Devuelve este objeto
}

alert(new BigUser().name);  // Godzilla, se devuelve ese objeto

				
			

En otro caso, con un return vacío:

				
					function SmallUser() {
  this.name = "John";

  return; // <-- Devuelve this
}

alert(new SmallUser().name);  // John

				
			

Normalmente, los constructores no usan return. La discusión sobre el retorno especial de objetos se menciona principalmente por integridad.

Omitiendo paréntesis

También es posible omitir paréntesis después de new:

				
					let user = new User; // <-- Sin paréntesis
// Igual que
let user = new User();
				
			

Aunque omitir paréntesis no se considera una «buena práctica», la especificación de JavaScript lo permite.

Métodos en constructores

Utilizar constructores de funciones nos proporciona mucha flexibilidad. No solo podemos agregar propiedades a this, sino también métodos.

Por ejemplo, el siguiente constructor new User(name) crea un objeto con el nombre proporcionado y un método sayHi:

				
					function User(name) {
  this.name = name;

  this.sayHi = function() {
    alert( "Mi nombre es: " + this.name );
  };
}

let john = new User("John");

john.sayHi(); // Mi nombre es: John

				
			

Para crear objetos más complejos, existe una sintaxis más avanzada: las clases, que discutiremos más adelante.

Resumen

  • Las funciones constructoras, o simplemente constructores, son funciones normales. Sin embargo, existe un convenio común de nombrarlas con la primera letra en mayúscula.
  • Los constructores deben ser invocados exclusivamente con new. Esta llamada implica la creación de un this vacío al inicio y devuelve este this lleno al final.
  • Podemos usar funciones constructoras para crear múltiples objetos similares.

JavaScript proporciona constructores de funciones para varios objetos integrados en el lenguaje, como Date para fechas, Set para conjuntos, y otros que planeamos estudiar más adelante.

Related Post

Deja una respuesta

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