Modullar

Eksport va Import

Eksport va import direktivalarining bir necha ko'rinishlari bor. Oldingi darsda eng oddiy holatini ko'rdik, endi ularning to'liq imkoniyatlarini chuqurroq o'rganamiz.

E'lon oldidan eksport (nomli eksport)

Istalgan e'lon (o'zgaruvchi, funksiya, klass) oldiga export qo'yib, uni eksport qilish mumkin:

// massivni eksport qilish
export let months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'];

// konstantani eksport qilish
export const MODULES_BECAME_STANDARD_YEAR = 2015;

// klassni eksport qilish
export class User {
  constructor(name) {
    this.name = name;
  }
}
Funksiya yoki klassdan oldingi exportdan keyin nuqta-vergul (;) qo'yilmaydi โ€” bu odatiy funksiya/klass e'loni, oddiy iboradan (statement) farq qiladi.

E'londan alohida eksport

Eksportni e'londan ajratib, alohida ro'yxat sifatida ham yozish mumkin. Bu qaysi funksiyalar tashqariga chiqarilganini bir joyda ko'rish uchun qulay:

// ๐Ÿ“ say.js
function sayHi(user) {
  alert(`Salom, ${user}!`);
}

function sayBye(user) {
  alert(`Xayr, ${user}!`);
}

export { sayHi, sayBye }; // ikkala funksiyani eksport qilamiz

Import

Odatda import qilinadigan narsalar ro'yxati jingalak qavs ichida ({...}) beriladi:

// ๐Ÿ“ main.js
import { sayHi, sayBye } from './say.js';

sayHi('Ali');  // Salom, Ali!
sayBye('Vali'); // Xayr, Vali!

Hammasini import qilish: import * as

Import qilinadigan narsalar ko'p bo'lsa, hammasini bitta obyektga * as <obj> ko'rinishida yig'ib olish mumkin:

// ๐Ÿ“ main.js
import * as say from './say.js';

say.sayHi('Ali');  // Salom, Ali!
say.sayBye('Vali'); // Xayr, Vali!
Hammasini import qilish (* as) qulay ko'rinsa-da, ko'pincha kerakli narsalarni aniq ro'yxatlab import qilish tavsiya etiladi. Sabablari: (1) zamonaviy build vositalari (webpack, Rollup) ishlatilmagan importlarni olib tashlab ("tree-shaking") build hajmini kichraytiradi; (2) aniq nomlar qaysi funksiya qayerdan kelganini ravshan ko'rsatadi va kodni tushunishni osonlashtiradi.

as bilan qayta nomlash (import)

as yordamida import qilinayotgan narsalarni boshqa nom bilan olish mumkin:

// ๐Ÿ“ main.js
import { sayHi as hi, sayBye as bye } from './say.js';

hi('Ali');  // Salom, Ali!
bye('Vali'); // Xayr, Vali!

as bilan qayta nomlash (export)

Xuddi shunday, eksport paytida ham nomni o'zgartirish mumkin:

// ๐Ÿ“ say.js
// ...
export { sayHi as hi, sayBye as bye };

// ๐Ÿ“ main.js
import * as say from './say.js';

say.hi('Ali');  // Salom, Ali!
say.bye('Vali'); // Xayr, Vali!

Export default (standart eksport)

Amalda modullar ikki turga bo'linadi: bir nechta funksiyani o'z ichiga oluvchi kutubxona modullari va bitta narsani (masalan, bitta klassni) e'lon qiluvchi modullar. Ikkinchi holat uchun default eksport qulay.

export default "bu modul faqat shu bitta narsani eksport qiladi" degani. Har bir faylda faqat bitta default eksport bo'lishi mumkin:

// ๐Ÿ“ user.js
export default class User {
  constructor(name) {
    this.name = name;
  }
}

Default eksportni import qilishda jingalak qavs ishlatilmaydi va istalgan nom berish mumkin:

// ๐Ÿ“ main.js
import User from './user.js'; // {User} emas, shunchaki User

new User('John');

Nomli eksportda import nomi eksport nomiga mos kelishi shart. Default eksportda esa nom ixtiyoriy โ€” quyidagilar teng:

import User from './user.js';
import MyUser from './user.js';
import Anything from './user.js';
// hammasi bir xil default eksportni oladi
Nomli eksportda har bir eksportning aniq nomi bor. Default eksportda esa nom yo'q, shuning uchun jamoada bir xil default'ga bir xil nom berish uchun kelishuv bo'lishi foydali.

"default" nomi

Ba'zan default eksportni belgilash uchun default nomidan foydalaniladi. Masalan, funksiyani e'londan alohida default eksport qilmoqchi bo'lsak:

// ๐Ÿ“ user.js
function sayHi(user) {
  alert(`Salom, ${user}!`);
}

// funksiyani default eksport sifatida belgilaymiz
export { sayHi as default };

Bitta modulda ham default, ham nomli eksportlar birga bo'lishi mumkin (garchi kamdan-kam ishlatilsa ham):

// ๐Ÿ“ user.js
export default class User {
  constructor(name) {
    this.name = name;
  }
}

export function sayHi(user) {
  alert(`Salom, ${user}!`);
}
// ๐Ÿ“ main.js
// default (User) va nomli (sayHi) eksportlarni birga olish:
import User, { sayHi } from './user.js';

new User('John');
sayHi('Ali');

import * as user orqali olsak, default eksport user.default nomi ostida bo'ladi:

// ๐Ÿ“ main.js
import * as user from './user.js';

let User = user.default; // default eksport
new User('John');
Default eksportga qat'iy nom yo'qligi kodni tushunishni qiyinlashtirishi mumkin. Ko'p tajribali dasturchilar aniqlik uchun asosan nomli eksportlarni afzal ko'radi. Lekin bu jamoa uslubiga bog'liq โ€” ikkalasi ham to'g'ri.

Re-export (qayta eksport)

export ... from ... sintaksisi import qilingan narsani darhol qayta eksport qilishga (ehtimol boshqa nom bilan) imkon beradi:

export { sayHi } from './say.js';        // sayHi ni qayta eksport
export { default as User } from './user.js'; // default ni User sifatida qayta eksport

Re-export nima uchun kerak? Tasavvur qiling, ko'p modullardan iborat "paket" (package) yozyapsiz. Ba'zi funksiyalar tashqi ishlatish uchun, ba'zilari esa ichki yordamchi. Butun paket funksionalligini yagona index.js orqali "kirish nuqtasi" (entry point) sifatida ochiq qilish qulay:

// ๐Ÿ“ auth/index.js

// login/logout ni import qilib, qayta eksport qilamiz
export { login, logout } from './helpers.js';

// default User ni User sifatida qayta eksport
export { default as User } from './user.js';

// ... boshqa modullardan ham

Endi paketdan foydalanuvchilar ichki tuzilmani bilmasdan, faqat index.jsdan import qiladi:

// paketni ishlatuvchi kod:
import { login, logout, User } from './auth/index.js';
Default eksportni qayta eksport qilishda ehtiyot bo'ling. export User from './user.js' โ€” ishlamaydi (sintaksis xatosi). Default'ni qayta eksport qilish uchun uni aniq ko'rsatish kerak: export { default as User } from './user.js'. Yoki barchasini birga: export * from './user.js' โ€” lekin bu defaultni chiqarib tashlaydi, faqat nomli eksportlarni qayta chiqaradi.

Import va export ko'tarilishi (hoisting)

import/export direktivalari qayerda yozilganidan qat'i nazar ishlaydi โ€” ular "ko'tariladi" (hoisted). Ammo uslub jihatidan ularni odatda fayl boshiga yozish tavsiya etiladi, chunki bu modul bog'liqliklarini bir qarashda ko'rish imkonini beradi.

Xulosa

Eksport turlari:

Import turlari: