Les directives dâexportation et dâimportation ont plusieurs variantes de syntaxe.
Dans lâarticle prĂ©cĂ©dent, nous avons vu une utilisation simple, explorons maintenant plus dâexemples.
Exporter avant les déclarations
Nous pouvons Ă©tiqueter nâimporte quelle dĂ©claration comme exportĂ©e en plaçant export devant elle, que ce soit une variable, une fonction ou une classe.
Par exemple, ici toutes les exportations sont valides:
// exporter un tableau
export let months = ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
// exporter une constante
export const MODULES_BECAME_STANDARD_YEAR = 2015;
// exporter une classe
export class User {
constructor(name) {
this.name = name;
}
}
Veuillez noter que lâexport avant une classe ou une fonction nâen fait pas une function expression. Câest toujours une fonction dĂ©claration, bien quâelle soit exportĂ©e.
La plupart des guides de bonnes pratiques JavaScript ne recommandent pas les points-virgules aprÚs les déclarations de fonctions et de classes.
Câest pourquoi il nâest pas nĂ©cessaire dâutiliser un point-virgule Ă la fin de export class et de export function:
export function sayHi(user) {
alert(`Hello, ${user}!`);
} // pas de ; Ă la fin
Exporter en dehors des déclarations
En outre, nous pouvons mettre lâexport sĂ©parĂ©ment.
Ici, nous dĂ©clarons dâabord, puis exportons:
// đ say.js
function sayHi(user) {
alert(`Hello, ${user}!`);
}
function sayBye(user) {
alert(`Bye, ${user}!`);
}
export {sayHi, sayBye}; // une liste de variables exportées
⊠Ou, techniquement, nous pourrions Ă©galement dĂ©finir les fonctions dâexport au-dessus des fonctions.
Import *
Habituellement, nous mettons une liste de ce quâil faut importer entre accolades import {...}, comme ceci:
// đ main.js
import {sayHi, sayBye} from './say.js';
sayHi('John'); // Hello, John!
sayBye('John'); // Bye, John!
Mais sâil y a beaucoup Ă importer, nous pouvons tout importer en tant quâobjet en utilisant import * as <obj>, par exemple:
// đ main.js
import * as say from './say.js';
say.sayHi('John');
say.sayBye('John');
Ă premiĂšre vue, âimporter toutâ semble ĂȘtre une chose tellement cool, simple a Ă©crire, pourquoi devrions-nous explicitement Ă©numĂ©rer ce que nous devons importer?
Eh bien, il y a quelques raisons.
- Lister explicitement ce quâil faut importer donne des noms plus courts :
sayHi()au lieu desay.sayHi(). - La liste explicite des importations donne un meilleur aperçu de la structure du code : ce qui est utilisĂ© et oĂč. Cela facilite la prise en charge du code et la refactorisation.
Les outils de construction modernes, tels que webpack et dâautres, regroupent les modules et les optimisent pour accĂ©lĂ©rer le chargement. Ils ont Ă©galement supprimĂ© les importations inutilisĂ©es.
Par exemple, si vous importer import * as library Ă partir dâune Ă©norme bibliothĂšque de codes, puis nâutilisez que quelques mĂ©thodes, celles qui ne sont pas utilisĂ©es [ne seront pas incluses] (https://github.com/webpack/webpack/tree/main/ examples/harmony-unused#examplejs) dans le bundle optimisĂ©.
Import âasâ
Nous pouvons également utiliser as pour importer sous différents noms.
Par exemple, importons sayHi dans la variable locale hi par souci de concision, et importons sayBye en bye:
// đ main.js
import {sayHi as hi, sayBye as bye} from './say.js';
hi('John'); // Hello, John!
bye('John'); // Bye, John!
Export âasâ
La syntaxe similaire existe pour lâexport.
Exportons les fonctions en tant que hi et bye:
// đ say.js
...
export {sayHi as hi, sayBye as bye};
Maintenant, hi et bye sont les noms Ă utiliser dans les importations:
// đ main.js
import * as say from './say.js';
say.hi('John'); // Hello, John!
say.bye('John'); // Bye, John!
Export default
En pratique, il existe principalement deux types de modules.
- Les modules qui contiennent une bibliothĂšque, un pack de fonctions, comme
say.jsci-dessus. - Les modules qui déclarent une seule entité, par exemple un module
user.jsqui exporte uniquement laclass User.
La deuxiĂšme approche est gĂ©nĂ©ralement privilĂ©giĂ©e, de sorte que chaque âchoseâ rĂ©side dans son propre module.
Naturellement, cela nĂ©cessite beaucoup de fichiers, car toute chose veut son propre module, mais ce nâest pas un problĂšme du tout. En fait, la navigation dans le code devient plus facile si les fichiers sont bien nommĂ©s et structurĂ©s en dossiers.
Les modules fournissent une syntaxe spĂ©ciale export default (âlâexportation par dĂ©fautâ) afin dâamĂ©liorer lâaspect âune chose par moduleâ.
Placez export default avant lâentitĂ© Ă exporter:
// đ user.js
export default class User { // ajouter juste "default"
constructor(name) {
this.name = name;
}
}
Il ne peut y avoir quâun seul export default par fichier.
⊠Et ensuite importez-le sans accolades:
// đ main.js
import User from './user.js'; // pas {User}, juste User
new User('John');
Les importations sans accolades sont plus agrĂ©ables. Une erreur courante lorsque vous commencez Ă utiliser des modules est dâoublier les accolades. Par consĂ©quent, rappelez-vous que lâimport nĂ©cessite des accolades pour les exportations nommĂ©es et ne les utilise pas pour celle par dĂ©faut.
| Export nommé | Export par défaut |
|---|---|
export class User {...} |
export default class User {...} |
import {User} from ... |
import User from ... |
Techniquement, nous pouvons avoir à la fois des exportations par défaut et des exportations nommées dans un seul module, mais dans la pratique, les gens ne les mélangent généralement pas. Un module a soit, des exports nommés, soit celui par défaut.
Comme il peut y avoir au plus une exportation par dĂ©faut par fichier, lâentitĂ© exportĂ©e peut ne pas avoir de nom.
Par exemple, ce sont toutes des exportations par défaut parfaitement valides:
export default class { // pas de nom de classe
constructor() { ... }
}
export default function(user) { // pas de nom de fonction
alert(`Hello, ${user}!`);
}
// exporter une seule valeur sans créer de variable
export default ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
Ne pas donner de nom, câest bien, car lâexport default est unique par fichier. Par consĂ©quent, lâimportation sans accolades sait ce quâil faut importer.
Sans defaut, une telle exportation donnerait une erreur:
export class { // Erreur! (un export autre que par défaut nécessite un nom)
constructor() {}
}
Le nom par âdefaultâ
Dans certaines situations, le mot clĂ© default est utilisĂ© pour rĂ©fĂ©rencer lâexportation par dĂ©faut.
Par exemple, pour exporter une fonction séparément de sa définition:
function sayHi(user) {
alert(`Hello, ${user}!`);
}
// comme si nous avions ajouté "export default" avant la fonction
export {sayHi as default};
Ou, dans un autre cas, supposons quâun module user.js exporte un Ă©lĂ©ment principal par âdĂ©fautâ et quelques Ă©lĂ©ments nommĂ©s (rarement le cas, mais ça arrive):
// đ user.js
export default class User {
constructor(name) {
this.name = name;
}
}
export function sayHi(user) {
alert(`Hello, ${user}!`);
}
Voici comment importer lâexportation par dĂ©faut avec celle nommĂ©e:
// đ main.js
import {default as User, sayHi} from './user.js';
new User('John');
Et, enfin, si vous importez tout * comme objet, la propriĂ©tĂ© default est exactement lâexportation par dĂ©faut:
// đ main.js
import * as user from './user.js';
let User = user.default; // l'exportation par défaut
new User('John');
Un mot contre les exportations par défaut
Les exportations nommĂ©es sont explicites. Ils nomment exactement ce quâils importent, nous avons donc ces informations, câest une bonne chose.
Les exportations nommées nous obligent à utiliser exactement le bon nom pour importer :
import {User} from './user.js';
// importer {MyUser} ne fonctionnera pas, le nom devrait ĂȘtre {User}
âŠAlors que pour une exportation par dĂ©faut, nous choisissons toujours le nom lors de lâimportation:
import User from './user.js'; // fonctionne
import MyUser from './user.js'; // fonctionne aussi
// n'importe quoi pourrait ĂȘtre importĂ© ..., cela continuera de fonctionner
Les membres de lâĂ©quipe peuvent donc utiliser des noms diffĂ©rents pour importer la mĂȘme chose, et ce nâest pas bien.
Habituellement, pour éviter cela et garder le code cohérent, il existe une rÚgle voulant que les variables importées correspondent aux noms de fichier, par exemple:
import User from './user.js';
import LoginForm from './loginForm.js';
import func from '/path/to/func.js';
...
NĂ©anmoins, certaines Ă©quipes considĂšrent quâil sâagit dâun grave inconvĂ©nient des exportations par dĂ©faut. Ils prĂ©fĂšrent donc toujours utiliser des exportations nommĂ©es. MĂȘme si une seule chose est exportĂ©e, elle est toujours exportĂ©e sous un nom, sans default.
Cela facilite également la réexportation (voir ci-dessous).
Réexportation
La syntaxe âre-exportâ export ... from ... permet dâimporter et dâexporter immĂ©diatement des Ă©lĂ©ments (Ă©ventuellement sous un autre nom), comme ceci:
export {sayHi} from './say.js'; // réexportez sayHi
export {default as User} from './user.js'; // réexportez default
Pourquoi cela peut ĂȘtre nĂ©cessaire ? Voyons un cas dâutilisation pratique.
Imaginez, nous Ă©crivons un âpackageâ: un dossier avec beaucoup de modules, avec une partie des fonctionnalitĂ©s exportĂ©es Ă lâextĂ©rieur (des outils comme NPM nous permettent de publier et de distribuer de tels packages, mais nous nâavons pas Ă les utiliser), et de nombreux modules ne sont que des âhelpersâ, destinĂ©s Ă une utilisation interne dans dâautres modules de package.
La structure de fichier pourrait ĂȘtre comme ceci :
auth/
index.js
user.js
helpers.js
tests/
login.js
providers/
github.js
facebook.js
...
Nous aimerions exposer les fonctionnalitĂ©s du paquet via un seul point dâentrĂ©e.
En dâautres termes, une personne souhaitant utiliser notre package ne doit importer que depuis le âfichier principalâ auth/index.js.
Comme ceci :
import {login, logout} from 'auth/index.js'
Le âfichier principalâ, auth / index.js exporte toutes les fonctionnalitĂ©s que nous aimerions fournir dans notre package.
LâidĂ©e est que les tiers, les dĂ©veloppeurs qui utilisent notre package, ne doivent pas se mĂȘler de sa structure interne, rechercher des fichiers dans notre dossier de packages. Nous nâexportons que ce qui est nĂ©cessaire dans auth / index.js et gardons le reste cachĂ© des regards indiscrets.
La fonctionnalitĂ© exportĂ©e Ă©tant dispersĂ©e dans le package, nous pouvons lâimporter dans auth / index.js et lâexporter:
// đ auth/index.js
// importer les login / logout et les exporter immédiatement
import {login, logout} from './helpers.js';
export {login, logout};
// importer par défaut en tant qu'utilisateur et l'exporter
import User from './user.js';
export {User};
...
Maintenant, les utilisateurs de notre paquet peuvent import {login} from "auth/index.js".
La syntaxe export ... from ... est juste une notation plus courte pour importer et exporter directement:
// đ auth/index.js
// re-export login/logout
export {login, logout} from './helpers.js';
// re-export l'exportation par défaut en tant qu'User
export {default as User} from './user.js';
...
La diffĂ©rence notable entre export ... from et import/export est que les modules rĂ©exportĂ©s ne sont pas disponibles dans le fichier actuel. Donc, dans lâexemple ci-dessus de auth/index.js, nous ne pouvons pas utiliser les fonctions login/logout rĂ©exportĂ©es.
RĂ©-exportation de lâexportation par dĂ©faut
Lâexportation par dĂ©faut nĂ©cessite un traitement sĂ©parĂ© lors de la rĂ©exportation.
Supposons que nous ayons user.js avec le export default class User et que nous souhaitons le réexporter :
// đ user.js
export default class User {
// ...
}
On peut y rencontrer deux problĂšmes :
-
export User from './user.js'çe ne fonctionnera pas⊠Cela conduirait Ă une erreur de syntaxe.Pour rĂ©exporter lâexportation par dĂ©faut, nous devrions Ă©crire
export {default as User}, comme dans lâexemple ci-dessus. -
export * from './user.js'ne rĂ©exporte que les exportations nommĂ©es, et ignore celle par dĂ©faut.Si nous souhaitons rĂ©exporter lâexport nommĂ© et lâexport par dĂ©faut, deux instructions sont nĂ©cessaires:
export * from './user.js'; // réexporter les exportations nommées export {default} from './user.js'; // réexporter l'exportation par défaut
Ces bizarreries de rĂ©exporter une exportation par dĂ©faut sont lâune des raisons pour lesquelles certains dĂ©veloppeurs nâaiment pas les exportations par dĂ©faut et prĂ©fĂšrent les exportations nommĂ©es.
Résumé
Voici tous les types dâexport que nous avons abordĂ©s dans ce chapitre et dans les chapitres prĂ©cĂ©dents.
Vous pouvez vĂ©rifier vous-mĂȘme en les lisant et en vous rappelant leur signification:
- Avant la dĂ©claration dâune classe / fonction / âŠ:
export [default] class/function/variable ...
- Exportation autonome:
export {x [as y], ...}.
- Réexportation:
export {x [as y], ...} from "module"export * from "module"(ne ré-exporte pas par défaut).export {default [as y]} from "module"(ré-export par défaut).
Import:
- Importations dâexports nommĂ©s :
import {x [as y], ...} from "module"
- Importation de lâexport par dĂ©faut :
import x from "module"import {default as x} from "module"
- Tout importer :
import * as obj from "module"
- Importer le module (son code sâexĂ©cute), mais ne lâaffecte pas Ă une variable :
import "module"
Nous pouvons mettre des dĂ©clarations import/export en haut ou en bas dâun script, cela nâa pas dâimportance.
Donc, techniquement, ce code est correct:
sayHi();
// ...
import {sayHi} from './say.js'; // importer Ă la fin du fichier
En pratique, les importations se font gĂ©nĂ©ralement au dĂ©but du fichier, mais ce nâest que pour des raisons de commoditĂ©.
Veuillez noter que les instructions import/export ne fonctionnent pas si elles sont Ă lâintĂ©rieur {...}.
Une importation conditionnelle, comme celle-ci, ne fonctionnera pas:
if (something) {
import {sayHi} from "./say.js"; // Erreur: l'importation doit ĂȘtre au plus haut niveau
}
âŠMais que se passe-t-il si nous devons vraiment importer quelque chose de maniĂšre conditionnelle? Ou au bon moment? Aimez-vous, charger un module sur demande, quand câest vraiment nĂ©cessaire?
Nous verrons les importations dynamiques dans le chapitre suivant.
Commentaires
<code>, pour plusieurs lignes â enveloppez-les avec la balise<pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepenâŠ)