Export e Import en JavaScript
Las directivas export
e import
tienen diversas variantes en su sintaxis.
En el artículo anterior vimos un uso sencillo, ahora exploraremos más ejemplos.
Exportación previa a las declaraciones
Podemos marcar cualquier declaración como exportada colocando export
antes, ya sea una variable, una función o una clase.
Por ejemplo, todas las exportaciones siguientes son válidas:
// exportar un array
export let months = ['Jan', 'Feb', 'Mar', 'Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
// exportar una constante
export const MODULES_BECAME_STANDARD_YEAR = 2015;
// exportar una clase
export class User {
constructor(name) {
this.name = name;
}
}
Sin punto y coma después de export class
o export function
Es importante tener en cuenta que export
antes de una clase o función no la convierte en una expresión de función. Sigue siendo una declaración de función, aunque exportada.
La mayoría de las guías de estilo de JavaScript no recomiendan el uso de punto y coma después de declarar funciones y clases.
Por esta razón, no es necesario un punto y coma al final de export class
o export function
:
export function sayHi(user) {
alert(`Hello, ${user}!`);
} // no ; al final
Exportación separada de la declaración
También podemos colocar export
por separado.
Aquí primero declaramos y luego exportamos:
// 📁 say.js
function sayHi(user) {
alert(`Hello, ${user}!`);
}
function sayBye(user) {
alert(`Bye, ${user}!`);
}
export {sayHi, sayBye}; // una lista de variables exportadas
Importar todo
Generalmente, listamos lo que queremos importar entre llaves import {...}
, de esta manera:
// 📁 main.js
import {sayHi, sayBye} from './say.js';
sayHi('John'); // Hello, John!
sayBye('John'); // Bye, John!
Pero si hay mucho para importar, podemos importar todo como un objeto utilizando import * as <obj>
, por ejemplo:
// 📁 main.js
import * as say from './say.js';
say.sayHi('John');
say.sayBye('John');
Importar con alias
También podemos usar as
para importar con nombres diferentes.
Por ejemplo, importemos sayHi
en la variable local hi
para brevedad, e importemos sayBye
como bye
:
// 📁 main.js
import {sayHi as hi, sayBye as bye} from './say.js';
hi('John'); // Hello, John!
bye('John'); // Bye, John!
Exportar con alias
Existe una sintaxis similar para exportar.
Exportemos funciones como hi
y bye
:
// 📁 say.js
export {sayHi as hi, sayBye as bye};
Ahora hi
y bye
son los nombres oficiales para ser utilizados en importaciones:
// 📁 main.js
import * as say from './say.js';
say.hi('John'); // Hello, John!
say.bye('John'); // Bye, John!
Exportación predeterminada
En la práctica, existen principalmente dos tipos de módulos:
- Módulos que contienen una librería, paquete de funciones, como
say.js
de arriba. - Módulos que declaran una entidad simple, por ejemplo, un módulo
user.js
que exporta únicamenteclass User
.
Principalmente, se prefiere el segundo enfoque, de modo que cada «cosa» reside en su propio módulo.
Naturalmente, eso requiere muchos archivos, ya que todo quiere su propio módulo, pero eso no es un problema en absoluto. En realidad, la navegación de código se vuelve más fácil si los archivos están bien nombrados y estructurados en carpetas.
Los módulos proporcionan una sintaxis especial export default
(«la exportación predeterminada») para que la forma de «una cosa por módulo» se vea mejor.
Poner export default
antes de la entidad a exportar:
// 📁 user.js
export default class User { // solo agregar "default"
constructor(name) {
this.name = name;
}
}
Solo puede existir una sola exportación predeterminada por archivo.
…Y luego importarlo sin llaves:
// 📁 main.js
import User from './user.js'; // no {User}, solo User
new User('John');
Las importaciones sin llaves se ven mejor. Un error común al comenzar a usar módulos es olvidarse de las llaves. Entonces, recuerde, import
necesita llaves para las exportaciones con nombre y no las necesita para la predeterminada.
Resumen
Aquí están todos los tipos de ‘exportación’ que cubrimos en este y en artículos anteriores:
- Antes de la declaración de clase/función/variable:
export [default] class/function/variable ...
- Exportación independiente:
export {x [as y], ...}.
- Reexportar:
export {x [as y], ...} from "module"
export * from "module" (no reexporta la predeterminada).
export {default [as y]} from "module" (reexporta la predeterminada).
Importación
- Importar exportaciones con nombre:
import {x [as y], ...} from "module"
- Importar la exportación predeterminada:
import x from "module"
import {default as x} from "module"
- Importar todo:
import * as obj from "module"
- Importar el módulo (su código se ejecuta), pero no asigna ninguna de las exportaciones a variables:
import "module"
Podemos poner las declaraciones import/export
en la parte superior o inferior de un script, eso no importa.
Entonces, técnicamente este código está bien:
sayHi();
// ...
import {sayHi} from './say.js'; // import al final del archivo
En la práctica, las importaciones generalmente se encuentran al comienzo del archivo, pero eso es solo para mayor comodidad.
Importación condicional
Las declaraciones de import/export
no funcionan si están dentro de un bloque {...}
.
Una importación condicional, como esta, no funcionará:
if (something) {
import {sayHi} from "./say.js"; // Error: import debe estar en nivel superior
}
…Pero, ¿qué pasa si realmente necesitamos importar algo condicionalmente? O en el momento adecuado? Por ejemplo, ¿cargar un módulo a pedido, cuando realmente se necesita?
Veremos importaciones dinámicas en el próximo artículo.