Spread va Rest operatori

~15 daq · JavaScript · Ob'ektlar va Massivlar

Muammodan boshlaylik

Ikkita massivni birlashtirish kerak. Yoki funksiya nechta argument olishini oldindan bilmaysiz. Yoki ob'ektni nusxalash kerak, lekin Object.assign({}, ...) yozish uzoq tuyuladi.

Bularning barchasi uchun JavaScript da bitta operator bor — uch nuqta .... Lekin u ikki xil joyda ikki xil ma'no anglatadi: spread va rest.


Spread operatori — yoyish

Spread ... — massiv yoki ob'ektni "yoyib" yuboradi. Idishdagi narsalarni stolga to'kib tashlagan kabi — ichidagi elementlar alohida-alohida chiqadi.

Massivda spread

const mevalar = ["olma", "nok", "uzum"];

console.log(mevalar);    // ["olma", "nok", "uzum"] — massiv
console.log(...mevalar); // "olma" "nok" "uzum" — alohida qiymatlar

Massivlarni birlashtirish:

const sabzavotlar = ["sabzi", "piyoz"];
const mevalar = ["olma", "nok"];

// Eski usul
const hammasi1 = sabzavotlar.concat(mevalar);

// Spread bilan
const hammasi2 = [...sabzavotlar, ...mevalar];

console.log(hammasi2); // ["sabzi", "piyoz", "olma", "nok"]

O'rtaga element qo'shish ham oson:

const boshida = [0, 1, 2];
const oxirida = [6, 7, 8];

const toʻliq = [...boshida, 3, 4, 5, ...oxirida];
console.log(toʻliq); // [0, 1, 2, 3, 4, 5, 6, 7, 8]

Massivni nusxalash:

const asl = [1, 2, 3];

// Xato usul — bir xil massivga havola
const nusxa1 = asl;
nusxa1.push(4);
console.log(asl); // [1, 2, 3, 4] — asl ham o'zgardi!

// To'g'ri — spread bilan yangi massiv
const nusxa2 = [...asl];
nusxa2.push(4);
console.log(asl);    // [1, 2, 3] — o'zgarmadi
console.log(nusxa2); // [1, 2, 3, 4]

Funksiyaga argument sifatida:

const sonlar = [3, 1, 4, 1, 5, 9, 2, 6];

// Math.max massiv qabul qilmaydi — alohida argumentlar kerak
console.log(Math.max(3, 1, 4, 1, 5, 9, 2, 6)); // 9

// Spread bilan massivni "yoyib" beramiz
console.log(Math.max(...sonlar)); // 9

Ob'ektda spread

const asosiy = { ism: "Jasur", yosh: 24 };
const qoshimcha = { shahar: "Toshkent", kasb: "Dasturchi" };

// Ob'ektlarni birlashtirish
const toʻliq = { ...asosiy, ...qoshimcha };
console.log(toʻliq);
// { ism: "Jasur", yosh: 24, shahar: "Toshkent", kasb: "Dasturchi" }

Ob'ektni nusxalash va yangilash:

const foydalanuvchi = { ism: "Jasur", yosh: 24, shahar: "Toshkent" };

// Faqat yosh ni o'zgartirgan yangi ob'ekt
const yangilangan = { ...foydalanuvchi, yosh: 25 };

console.log(foydalanuvchi); // { ism: "Jasur", yosh: 24, shahar: "Toshkent" }
console.log(yangilangan);   // { ism: "Jasur", yosh: 25, shahar: "Toshkent" }

Bir xil kalit ikki marta bo'lsa — keyingisi ustun keladi. Shuning uchun yosh: 25 ni oxirida yozdik.

Bu pattern React va boshqa frameworklarda state yangilashda juda ko'p ishlatiladi:

const state = { isLoading: false, xato: null, maʼlumot: [] };

// Faqat isLoading ni o'zgartir, qolganlarini saqlb qol
const yangiState = { ...state, isLoading: true };

Rest operatori — yig'ish

Rest ... — spread ning aksi. U "qolgan narsalarni yig'ib, massivga joylashtir" degani.

Tashqi ko'rinish bir xil — ... — lekin ishlashi teskari: spread yoyadi, rest yig'adi.

Funksiya parametrlarida rest

Rest operatori funksiya nechta argument olishini oldindan bilmasangiz ishlatiladi:

function yig'indiHisobla(...sonlar) {
  // sonlar — barcha argumentlar massivi
  return sonlar.reduce((jami, son) => jami + son, 0);
}

console.log(yig'indiHisobla(1, 2));          // 3
console.log(yig'indiHisobla(1, 2, 3, 4, 5)); // 15
console.log(yig'indiHisobla(10));             // 10

Birinchi argumentlar alohida, qolganlari rest:

function xabarYubor(kimga, mavzu, ...qoʻshimchalar) {
  console.log(`Kimga: ${kimga}`);
  console.log(`Mavzu: ${mavzu}`);
  console.log(`Qo'shimchalar: ${qoʻshimchalar}`);
}

xabarYubor("Ali", "Salom", "rasm.jpg", "hujjat.pdf", "video.mp4");
// Kimga: Ali
// Mavzu: Salom
// Qo'shimchalar: rasm.jpg,hujjat.pdf,video.mp4

Rest har doim eng oxirida bo'lishi kerak — undan keyin boshqa parametr bo'lmaydi.

Destructuring da rest

Oldingi darsda ko'rgan edik — destructuring da ...rest qolgan elementlarni oladi:

// Massivda
const [birinchi, ikkinchi, ...qolganlar] = [1, 2, 3, 4, 5];
console.log(birinchi);  // 1
console.log:ikkinchi);  // 2
console.log(qolganlar); // [3, 4, 5]

// Ob'ektda
const { ism, ...qolganlar2 } = { ism: "Jasur", yosh: 24, shahar: "Toshkent" };
console.log(ism);        // "Jasur"
console.log(qolganlar2); // { yosh: 24, shahar: "Toshkent" }

Spread vs Rest — farqi

Ikkisi ham ... — lekin kontekstga qarab farq qiladi:

Spread — ma'lumotni yoyadi:
  [...massiv]          → massivni yoyadi
  {...ob'ekt}          → ob'ektni yoyadi
  funksiya(...massiv)  → argumentlarni yoyadi

Rest — ma'lumotni yig'adi:
  function f(...args)       → argumentlarni massivga yig'adi
  const [a, ...rest] = arr  → qolganlarni massivga yig'adi
  const {a, ...rest} = obj  → qolganlarni ob'ektga yig'adi

Qoida oddiy: ... chap tomonda (qabul qilayotgan joyda) — rest. ... o'ng tomonda yoki argument sifatida — spread.

// Spread — o'ng tomonda, yoyadi
const arr = [...boshqa];
funksiya(...arr);

// Rest — chap tomonda, yig'adi
const [...qolganlar] = massiv;
function f(...args) {}

Amaliy misollar

Massivdan dublikatlarni olib tashlash:

const takrorli = [1, 2, 2, 3, 3, 3, 4];

const unikal = [...new Set(takrorli)];
console.log(unikal); // [1, 2, 3, 4]

String ni massivga aylantirish:

const soʻz = "Salom";
const harflar = [...soʻz];
console.log(harflar); // ["S", "a", "l", "o", "m"]

Ob'ektdan xususiyat olib tashlab nusxalash:

const foydalanuvchi = {
  id: 1,
  ism: "Jasur",
  parol: "maxfiy123",
  email: "jasur@example.com"
};

// parol ni olib tashlab, qolganini olish
const { parol, ...xavfsizMaʼlumot } = foydalanuvchi;

console.log(xavfsizMaʼlumot);
// { id: 1, ism: "Jasur", email: "jasur@example.com" }

Tez-tez uchraydigan xatolar

Rest oxirida bo'lishi kerak

// Xato — rest o'rtada bo'lmaydi
function f(...args, oxirgi) {} // SyntaxError

// To'g'ri — rest eng oxirida
function f(birinchi, ...args) {}

Spread chuqur nusxa qilmaydi

const asl = { ism: "Jasur", manzil: { shahar: "Toshkent" } };

const nusxa = { ...asl };
nusxa.manzil.shahar = "Samarqand"; // ichki ob'ektni o'zgartirdi

console.log(asl.manzil.shahar); // "Samarqand" — asl ham o'zgardi!

Spread faqat birinchi qatlamni nusxalaydi. Ichki ob'ektlar hali ham bir xil xotira manzilini ko'rsatadi. Chuqur nusxa uchun structuredClone() ishlatiladi:

const chuqurNusxa = structuredClone(asl);
chuqurNusxa.manzil.shahar = "Samarqand";

console.log(asl.manzil.shahar); // "Toshkent" — o'zgarmadi

Ob'ektni massivga spread qilish

const ob'ekt = { a: 1, b: 2 };

// Xato — ob'ekt massivga spread qilinmaydi
const arr = [...ob'ekt]; // TypeError

// To'g'ri — Object.values dan foydalaning
const arr2 = [...Object.values(ob'ekt)]; // [1, 2]

Xulosa

... operatori ikki xil vazifani bajaradi — qayerda ishlatilganiga qarab.

Spread — yoyadi. Massiv yoki ob'ekt elementlarini "chiqarib tashlaydi". Birlashtirish, nusxalash, funksiyaga argument sifatida uzatish uchun.

Rest — yig'adi. Qolgan argumentlar yoki elementlarni massiv yoki ob'ektga yig'adi. Funksiya parametrlarida va destructuring da ishlatiladi.

Ikkalasi ham faqat birinchi qatlamni ko'chiradi — ichki ob'ektlar havolasi bo'yicha qoladi. Chuqur nusxa kerak bo'lsa structuredClone() ishlatiladi.


Keyingi dars

22-dars: Massivlar — yaratish va asosiy metodlar — push, pop, shift, unshift, splice, slice