IlmHamroh
JavaScript Full-stack/8-qism. JavaScript asoslari59/61-dars17 daqiqa
Mundarija (35)

JavaScript spread va rest operatori: uch nuqta ... ning ikki vazifasi

Qisqacha: Uch nuqta ... JavaScript'da ikki xil ish qiladi. Spread (yoyish) massiv, satr yoki obyektni bo'laklarga "sochib" yuboradi: [...a, ...b], { ...obyekt }, Math.max(...narxlar). Rest (yig'ish) esa bir nechta qiymatni bitta massiv yoki obyektga yig'adi: function jami(...sonlar). Qaysi biri ekanini ... turgan joy hal qiladi: qiymat kerak joyda — spread, o'zgaruvchi yaratiladigan joyda — rest.

Bu darsda

  • Massivni spread bilan nusxalay, birlashtira va unga element qo'sha olasiz.
  • Obyektni nusxalab, birlashtirib, bitta xususiyatini yangilay olasiz va "kim ustun" tartibini bilasiz.
  • Math.max(...narxlar) kabi massivni argumentlarga yoyasiz.
  • Istalgan sondagi argument qabul qiladigan funksiyani rest parametr bilan yozasiz.
  • Spread va rest'ni bir qarashda farqlaysiz va spread nusxasi nega "sayoz" ekanini tushunasiz.

Oldin bilishingiz kerak: Massiv destructuring, Obyekt destructuring, Kesish, birlashtirish va matnga aylantirish, Havola semantikasi, Parametrlar va argumentlar.

1. Nega bu kerak?

Oldingi ikki darsda ...qolgan ni ko'rdingiz: u destructuringda "qolgan hammasi"ni yig'ardi. Bu uch nuqtaning faqat bitta yuzi. Keling, uch kichik muammoni ko'ramiz.

Birinchi muammo. Bozordagi narxlar massivida eng kattasini topmoqchisiz. Math.max ni bilasiz:

js
const narxlar = [12000, 8000, 15000];

console.log(Math.max(12000, 8000, 15000)); // 15000
console.log(Math.max(narxlar)); // NaN

Math.max sonlarni alohida-alohida kutadi. Unga butun massivni bersangiz, NaN qaytaradi. Massivda 100 ta narx bo'lsa, ularni qo'lda yozib chiqmaysiz-ku.

Ikkinchi muammo. To'yga ikki ro'yxat bor: kuyov tomon va kelin tomon mehmonlari. Ularni bitta ro'yxatga birlashtirib, boshiga "Imom domla"ni qo'shish kerak. Asl ro'yxatlar esa buzilmasin.

Uchinchi muammo. Funksiya kerak: jami(5000, 3000) ham, jami(1000, 2000, 3000, 4000) ham ishlasin. Argumentlar soni oldindan noma'lum.

Uchala muammoni bitta belgi — ... — hal qiladi.

2. Bitta belgi, ikki vazifa

Uch nuqta ... ikki qarama-qarshi ish qiladi:

  • Yoyish (spread) — bitta "quti"ni ochib, ichidagilarni birma-bir chiqarib qo'yadi.
  • Yig'ish (rest) — birma-bir turgan qiymatlarni bitta "quti"ga yig'adi.

Hayotdan o'xshatish: bir qop yong'oq. Qopni stolga ag'darsangiz, yong'oqlar yoyilib ketadi — bu spread. Stoldagi yong'oqlarni qaytib qopga solsangiz — bu rest. Qop ham, yong'oq ham bir xil, faqat harakat yo'nalishi teskari.

Bu darsning oxirgi qismida ularni qanday farqlashni aniq qoida bilan ko'ramiz. Avval har birini alohida o'rganamiz.

3. Massivda spread

3.1 Nusxa olish

Kesish va birlashtirish darsida [...massiv] bilan nusxa olishni qisqacha ko'rgandingiz. Endi nega shunday ishlashini tushunamiz:

js
const mevalar = ["olma", "nok"];
const nusxa = [...mevalar];

nusxa.push("anor");

console.log(mevalar); // [ 'olma', 'nok' ]
console.log(nusxa); // [ 'olma', 'nok', 'anor' ]
console.log(nusxa === mevalar); // false

[...mevalar] shunday o'qiladi: "yangi [ ] massiv yasa va ichiga mevalar ning elementlarini birma-bir yoyib chiq". Natijada ["olma", "nok"] — lekin bu yangi massiv.

Havola semantikasi darsini eslang: const nusxa = mevalar; deb yozsak, yangi massiv paydo bo'lmasdi — ikki nom bitta massivga qarab qolardi. Spread esa haqiqatan yangi massiv yasaydi. Shuning uchun nusxa ga push qilish mevalar ga ta'sir qilmadi, === esa false berdi.

3.2 Birlashtirish

To'y mehmonlarini birlashtiramiz:

js
const kuyovTomon = ["Anvar", "Bobur"];
const kelinTomon = ["Gulnora", "Dildora"];

const mehmonlar = [...kuyovTomon, ...kelinTomon];
console.log(mehmonlar);
// [ 'Anvar', 'Bobur', 'Gulnora', 'Dildora' ]

Ikkala massiv yangi massiv ichida yoyildi. Bu kuyovTomon.concat(kelinTomon) bilan bir xil natija. Farqi — spread bilan ikkitadan ko'p massivni ham, alohida qiymatlarni ham bitta yozuvda aralashtirish mumkin.

3.3 Boshiga, oxiriga, o'rtasiga qo'shish

Spread'ni massiv ichida istalgan joyga qo'yasiz. Oddiy qiymatlar bilan aralashtirsa ham bo'ladi:

js
const kuyovTomon = ["Anvar", "Bobur"];
const kelinTomon = ["Gulnora", "Dildora"];

const royxat = ["Imom domla", ...kuyovTomon, "Mezbon", ...kelinTomon];
console.log(royxat);

Konsolda:

text
[ 'Imom domla', 'Anvar', 'Bobur', 'Mezbon', 'Gulnora', 'Dildora' ]

"Imom domla" boshiga, "Mezbon" ikki ro'yxat o'rtasiga tushdi. Asl kuyovTomon va kelinTomon o'zgarmadi.

Bu unshift va push dan muhim farq qiladi. Ular asl massivni o'zgartiradi (mutatsiya). Spread esa aslini tegmasdan, yangi massiv beradi:

Maqsad Aslini o'zgartiradi Yangi massiv beradi
Oxiriga qo'shish royxat.push(x) [...royxat, x]
Boshiga qo'shish royxat.unshift(x) [x, ...royxat]
Ikki massivni qo'shish — [...a, ...b]

Tekshirib ko'ring: Konsolda nima chiqadi?

js
const a = [1, 2];
const b = [0, ...a, 3];
console.log(a.length, b.length);
Javob

2 4. b — yangi massiv: [0, 1, 2, 3], 4 ta element. a esa o'zgarmadi, unda avvalgidek 2 ta element.

4. Funksiya chaqiruvida spread

4.1 Math.max(...narxlar)

Birinchi muammoga qaytamiz:

js
const narxlar = [12000, 8000, 15000];

console.log(Math.max(...narxlar)); // 15000
console.log(Math.min(...narxlar)); // 8000

Math.max(...narxlar) — "massivni ochib, elementlarini argument sifatida alohida-alohida ber". JavaScript uchun bu aynan Math.max(12000, 8000, 15000) yozuvi bilan bir xil.

Massiv bo'sh bo'lsa, natija g'alati chiqadi:

js
const narxlar = [];

console.log(Math.max(...narxlar)); // -Infinity
console.log(Math.min(...narxlar)); // Infinity

Math.max() ga hech narsa berilmadi — u "eng kichik mumkin bo'lgan son"ni, -Infinity ni qaytaradi. Real kodda massiv bo'sh bo'lishi mumkin bo'lsa, avval length ni tekshiring.

Diqqat: Juda katta massivni (yuz minglab element) funksiya argumentlariga yoyib bo'lmaydi. Masalan, 130 000 ta sonli massivda Math.max(...katta) shunday xato beradi: RangeError: Maximum call stack size exceeded. Argumentlar soniga chegara bor. Bunday massivda eng kattasini oddiy for sikl bilan toping.

4.2 Istalgan funksiyaga

Spread faqat Math.max bilan emas, har qanday funksiya chaqiruvida ishlaydi. Masalan, o'zingiz yozgan funksiyaga:

js
function manzilYoz(shahar, tuman, kocha) {
  return `${shahar}, ${tuman}, ${kocha}`;
}

const qismlar = ["Toshkent", "Chilonzor", "Bunyodkor 5"];
console.log(manzilYoz(...qismlar));
// Toshkent, Chilonzor, Bunyodkor 5

Massivning 0-elementi shahar ga, 1-elementi tuman ga, 2-elementi kocha ga tushdi — tartib bo'yicha.

Yana bir foydali holat — bir massivning hamma elementini boshqasiga push qilish:

js
const savat = ["non"];
const yangiXaridlar = ["sut", "qatiq"];

savat.push(...yangiXaridlar);
console.log(savat); // [ 'non', 'sut', 'qatiq' ]

push(...yangiXaridlar) → push("sut", "qatiq"). E'tibor bering: bu yerda savat ning o'zi o'zgardi, chunki push — mutatsiya qiladigan metod. Spread faqat argumentlarni yoyib berdi.

Tekshirib ko'ring: savat.push(yangiXaridlar) (uch nuqtasiz) yozilsa, savat qanday bo'ladi?

Javob

["non", ["sut", "qatiq"]]. Uch nuqtasiz butun massiv bitta element sifatida qo'shiladi — massiv ichida massiv hosil bo'ladi. savat.length 3 emas, 2 bo'ladi.

5. Satrni belgilarga yoyish

Spread faqat massivni emas, har qanday iterable ni yoya oladi. for...of darsida ko'rgandingiz: satr ham iterable. Demak, uni belgilarga yoyish mumkin:

js
const soz = "salom";

console.log([...soz]); // [ 's', 'a', 'l', 'o', 'm' ]

Siz split("") ni ham bilasiz — u ham satrni harflarga bo'ladi. Lekin Unicode darsida muhim farqni ko'rgandik. Emoji bor matnda natija boshqacha:

js
const xabar = "Hi👋";

console.log(xabar.split("").length); // 4
console.log([...xabar].length); // 3

split("") kod birliklari bo'yicha bo'ladi va emoji'ni ikki "yarim"ga ajratib yuboradi. [...xabar] esa kod nuqtalari bo'yicha bo'ladi — emoji butun qoladi. Unicode darsida [...matn] ni "tayyor formula" sifatida ishlatgan edik. Endi bilasiz: bu spread — satrni belgilarga yoyib, yangi massivga yig'ish.

Maslahat: Matnda emoji yoki boshqa murakkab belgi bo'lishi mumkin bo'lsa (Telegram xabarlari, foydalanuvchi ismlari), split("") o'rniga [...matn] ishlating.

Oddiy obyekt esa iterable emas. Uni massivga yoyib bo'lmaydi:

js
const mahsulot = { nomi: "Olma", narx: 12000 };

const royxat = [...mahsulot];
text
TypeError: mahsulot is not iterable

"mahsulot — iterable emas". Obyektni massivga aylantirish kerak bo'lsa, Object.values yoki Object.entries ishlating. Obyektni obyektga yoyish esa mumkin — hozir ko'ramiz.

6. Obyektda spread

6.1 Nusxa olish

Obyektni ham xuddi massiv kabi nusxalash mumkin — jingalak qavs ichida:

js
const mahsulot = { nomi: "Olma", narx: 12000 };
const nusxa = { ...mahsulot };

nusxa.narx = 10000;

console.log(mahsulot.narx); // 12000
console.log(nusxa.narx); // 10000
console.log(nusxa === mahsulot); // false

{ ...mahsulot } — "yangi obyekt yasa va ichiga mahsulot ning barcha kalit-qiymatlarini yoyib chiq". Yangi obyekt — demak, uni o'zgartirish aslga ta'sir qilmaydi.

6.2 Birlashtirish va "kim ustun"

Ikki obyektni bittaga birlashtiramiz:

js
const asosiy = { ism: "Ali", yosh: 19 };
const aloqa = { shahar: "Buxoro", tel: "90 111 22 33" };

const profil = { ...asosiy, ...aloqa };
console.log(profil);

Konsolda:

text
{ ism: 'Ali', yosh: 19, shahar: 'Buxoro', tel: '90 111 22 33' }

Agar ikkala obyektda bir xil kalit bo'lsa-chi? Unda qoida oddiy: keyingisi ustun. JavaScript kalitlarni chapdan o'ngga yozib boradi. Bir xil kalit ikkinchi marta kelsa, eski qiymatning ustidan yozadi:

js
const standart = { til: "uz", mavzu: "yorug'", ovoz: 50 };
const tanlov = { mavzu: "qorong'i" };

const sozlama = { ...standart, ...tanlov };
console.log(sozlama); // { til: 'uz', mavzu: "qorong'i", ovoz: 50 }

mavzu ikki marta keldi: avval "yorug'", keyin "qorong'i". Oxirgisi qoldi. Foydalanuvchi o'zgartirmagan sozlamalar esa (til, ovoz) standartdan olindi.

Bu naqsh real loyihalarda juda ko'p ishlatiladi: avval standart qiymatlar, keyin foydalanuvchi tanlovi. Tartibni teskari yozsangiz, foydalanuvchi tanlovi yo'qoladi:

js
const standart = { til: "uz", mavzu: "yorug'", ovoz: 50 };
const tanlov = { mavzu: "qorong'i" };

const sozlama = { ...tanlov, ...standart }; // ❌ tartib teskari
console.log(sozlama.mavzu); // yorug'

Hayotdan o'xshatish: devorga e'lon yopishtirish. Keyingi e'lon oldingisining ustiga yopishtiriladi. Odamlar eng ustidagini — oxirgisini — o'qiydi.

6.3 Bitta xususiyatni yangilash

Spread'dan keyin oddiy kalit yozsangiz, u ham "keyingi" hisoblanadi va ustun keladi:

js
const mahsulot = { nomi: "Olma", narx: 12000, soni: 40 };

const arzonlashgan = { ...mahsulot, narx: 10000 };

console.log(arzonlashgan); // { nomi: 'Olma', narx: 10000, soni: 40 }
console.log(mahsulot.narx); // 12000

"mahsulot ning nusxasi, lekin narxi 10 000" — bitta qatorda. Asl mahsulot o'zgarmadi. Yangi kalit qo'shish ham shunday: { ...mahsulot, chegirma: true }.

Aslini o'zgartirmasdan yangi nusxa yasash — kasbiy dasturlashda juda muhim odat. Keyinchalik React bilan ishlaganda bu majburiy qoidaga aylanadi.

Diqqat: Bu yerda ham tartib muhim. { narx: 10000, ...mahsulot } yozsangiz, spread keyin keladi va mahsulot dagi eski narx (12000) ustun chiqadi. Yangi qiymat har doim spread'dan keyin yoziladi.

6.4 Obyektga nimalarni yoyish mumkin?

Obyekt spread massivnikidan yumshoqroq. null va undefined ni yoysangiz — xato emas, shunchaki hech narsa qo'shilmaydi:

js
const qoshimcha = null;

const buyurtma = { taom: "Osh", ...qoshimcha };
console.log(buyurtma); // { taom: 'Osh' }

Bu qulay: ixtiyoriy obyekt bo'lsa ham, bo'lmasa ham kod ishlayveradi. Massivda esa [...null] — TypeError: null is not iterable. Bu farqni eslab qoling.

Maslahat: Massiv yoki satrni obyektga yoysangiz, indekslar kalit bo'lib qoladi: { ..."ab" } → { '0': 'a', '1': 'b' }. Bunga ataylab kam ehtiyoj bo'ladi, lekin xato natijani ko'rsangiz tanib olasiz.

Tekshirib ko'ring: const x = { a: 1, b: 2, ...{ b: 5, c: 3 } }; — x nimaga teng?

Javob

{ a: 1, b: 5, c: 3 }. Avval a: 1 va b: 2 yozildi. Keyin spread b: 5 va c: 3 ni qo'shdi. b ikkinchi marta keldi, shuning uchun keyingisi — 5 — ustun.

7. Rest parametrlar

7.1 Istalgan sondagi argument

Endi uchinchi muammo: argumentlar soni oldindan noma'lum funksiya.

js
function jami(...narxlar) {
  let summa = 0;
  for (const narx of narxlar) {
    summa += narx;
  }
  return summa;
}

console.log(jami(5000, 3000)); // 8000
console.log(jami(1000, 2000, 3000, 4000)); // 10000
console.log(jami()); // 0

...narxlar — rest parametr. U chaqiruvda berilgan barcha argumentlarni bitta massivga yig'adi. jami(5000, 3000) da narxlar — [5000, 3000]. jami() da — bo'sh massiv [].

Bu yerda ... teskari ishladi: yoymadi, balki yig'di. Birma-bir kelgan qiymatlar bitta qutiga tushdi.

7.2 Oddiy parametr va rest birga

Birinchi bir nechta argument alohida kerak, qolgani esa ro'yxat bo'lsa — oddiy parametrlarni avval, rest'ni oxirida yozasiz:

js
function buyurtmaBer(mijoz, ...taomlar) {
  console.log(`Mijoz: ${mijoz}`);
  console.log(`Taomlar: ${taomlar.join(", ")}`);
  console.log(`Soni: ${taomlar.length}`);
}

buyurtmaBer("Jasur", "Osh", "Somsa", "Choy");

Konsolda:

text
Mijoz: Jasur
Taomlar: Osh, Somsa, Choy
Soni: 3

Birinchi argument mijoz ga tushdi, qolgan uchtasi taomlar massiviga yig'ildi. Massiv destructuringdagi [birinchi, ...qolgan] bilan bir xil g'oya.

7.3 Rest — arguments ning zamonaviy o'rni

Parametrlar darsida eski arguments ni ko'rgandingiz va "uning o'rnini rest parametrlar egallagan" degan edik. Mana nega:

arguments Rest ...nom
Nima u Massivga o'xshash obyekt Haqiqiy massiv
Nomi Doim arguments O'zingiz tanlaysiz
Arrow funksiyada Yo'q Ishlaydi
Nimani oladi Hamma argumentni Faqat "qolgan"ini

Arrow funksiyada arguments umuman yo'qligini ko'ramiz:

js
const jami = () => arguments.length;

console.log(jami(1, 2, 3));
text
ReferenceError: arguments is not defined

"arguments aniqlanmagan". Bu xato brauzerda va modul faylda (.mjs) chiqadi. node fayl.js bilan ishga tushirsangiz, xato o'rniga kutilmagan son (masalan, 5) chiqishi mumkin: Node faylni o'zining ichki funksiyasiga o'raydi va arrow o'sha funksiyaning arguments ini oladi. Ikkala holatda ham arrow o'z argumentlarini (1, 2, 3) ko'rmaydi.

Arrow funksiyada rest parametr ishlating:

js
const jami = (...sonlar) => sonlar.length;

console.log(jami(1, 2, 3)); // 3

7.4 Rest parametr qoidalari

Rest parametr faqat bitta bo'ladi va oxirida turadi:

js
function tanlov(...nomzodlar, golib) {}
text
SyntaxError: Rest parameter must be last formal parameter

Tarjimasi: "Rest parametr oxirgi rasmiy parametr bo'lishi shart". Mantiqiy: rest hamma qolganini yutib yuboradi, undan keyingi parametrga hech narsa qolmaydi.

Yana bir mayda detal. Funksiyaning length xususiyati rest parametrni sanamaydi:

js
function buyurtmaBer(mijoz, ...taomlar) {}

console.log(buyurtmaBer.length); // 1

Tekshirib ko'ring: function f(a, ...b) {} ni f(1) deb chaqirsak, b nimaga teng?

Javob

[] — bo'sh massiv. 1 a ga tushdi, qolgan argument yo'q. Rest parametr hech qachon undefined bo'lmaydi — eng kamida bo'sh massiv.

8. Spread yoki rest? Farqlash qoidasi

Ikkalasi ham ... bilan yoziladi. Qaysi biri ekanini turgan joyi hal qiladi.

Qoida: ... qiymat kerak bo'lgan joyda tursa — spread (yoyadi). O'zgaruvchi yoki parametr yaratiladigan joyda tursa — rest (yig'adi).

Qayerda Nima Misol
Massiv yoki obyekt yasashda Spread [...a, 5], { ...o }
Funksiya chaqiruvida Spread Math.max(...narxlar)
Funksiya parametrlarida Rest function f(...sonlar)
= ning chap tomonida Rest const [a, ...q] = m;

Yodda saqlash uchun: = ning o'ng tomoni va chaqiruv qavslari — "beruvchi" tomon, u yerda spread. = ning chap tomoni va e'lon qavslari — "oluvchi" tomon, u yerda rest.

Ikkalasi bitta funksiyada ham uchraydi:

js
function engQimmat(...narxlar) {
  return Math.max(...narxlar);
}

console.log(engQimmat(12000, 8000, 15000)); // 15000

Birinchi ...narxlar — parametrda, demak rest: argumentlarni massivga yig'di. Ikkinchi ...narxlar — chaqiruvda, demak spread: o'sha massivni yana alohida qiymatlarga yoydi.

Tekshirib ko'ring: Har bir qatordagi ... — spread yoki rest?

js
const [bosh, ...dum] = royxat;          // 1
const nusxa = { ...profil };             // 2
const f = (...args) => args;             // 3
console.log(...royxat);                  // 4
Javob

1 — rest (= ning chap tomonida, o'zgaruvchi yaratyapti). 2 — spread (obyekt yasashda, qiymat joyida). 3 — rest (parametrlar ro'yxatida). 4 — spread (funksiya chaqiruvida).

9. Diqqat: spread nusxasi — sayoz

Spread yangi massiv yoki obyekt yasaydi. Lekin faqat birinchi qavatni. Ichma-ich obyekt bo'lsa, u nusxalanmaydi — faqat havolasi ko'chadi:

js
const talaba = {
  ism: "Malika",
  manzil: { shahar: "Namangan" },
};

const nusxa = { ...talaba };
nusxa.ism = "Sevara";
nusxa.manzil.shahar = "Andijon";

console.log(talaba.ism); // Malika
console.log(talaba.manzil.shahar); // Andijon

ism — satr, u haqiqatan nusxalandi. nusxa.ism ni o'zgartirish aslga ta'sir qilmadi. manzil esa obyekt. Spread uni yangi obyekt qilib yasamadi — nusxa.manzil va talaba.manzil bitta obyektga qarab turibdi. Shuning uchun shahar ikkalasida ham o'zgardi.

Bunday nusxa sayoz nusxa (shallow copy) deyiladi: faqat yuzasi yangi, ichi eski. Massivlarda ham xuddi shunday: [...massiv] ichidagi obyektlarni nusxalamaydi.

Hozircha shuni eslab qoling: ichma-ich obyekt bo'lsa, spread nusxasi to'liq mustaqil emas. Bu muammoni qanday hal qilishni — chuqur nusxa va structuredClone ni — Sayoz va chuqur nusxalash darsida batafsil ko'ramiz.

10. Ko'p uchraydigan xatolar

10.1 Massivni spread'siz berish

Math.max(narxlar) → NaN. Funksiya alohida sonlarni kutgan, siz esa bitta massiv berdingiz. Tuzatish: Math.max(...narxlar).

10.2 Obyektni massivga yoki argumentlarga yoyish

[...obyekt] → TypeError: obyekt is not iterable. Funksiya chaqiruvida esa xabar boshqacha:

js
const mahsulot = { nomi: "Olma", narx: 12000 };

console.log(Math.max(...mahsulot));
text
TypeError: Spread syntax requires ...iterable[Symbol.iterator] to be a function

Tarjimasi: "Spread sintaksisi iterable narsani talab qiladi". Xabar texnik va qo'rqituvchi ko'rinadi — Symbol.iterator ni hozir bilishingiz shart emas, uni keyinroq o'rganamiz. Ma'nosi oddiy: siz yoymoqchi bo'lgan narsa massiv yoki satr emas. Odatda bu oddiy obyekt yoki undefined bo'ladi.

10.3 Birlashtirishda tartibni adashtirish

{ ...tanlov, ...standart } — xato chiqmaydi, lekin foydalanuvchi tanlovi standart bilan bosilib ketadi. Qoida: ustun bo'lishi kerak bo'lgan obyekt oxirida.

10.4 Rest oxirida emas

SyntaxError: Rest parameter must be last formal parameter (funksiyada) yoki Rest element must be last element (destructuringda). Tuzatish — ... li qismni oxirga ko'chiring.

10.5 Spread nusxasini to'liq mustaqil deb o'ylash

Ichma-ich obyektli nusxani o'zgartirsangiz, asl ham o'zgaradi. Bu xato matn bermaydi — natija "sehrli" tarzda buziladi. Ichma-ich ma'lumotda ehtiyot bo'ling.

11. Mashqlar

1-mashq (oson): Menyu

Ikki massiv bor: issiqTaomlar = ["Osh", "Lag'mon"] va ichimliklar = ["Choy", "Kompot"]. Spread bilan yangi menyu massivini yasang: boshida "Non", keyin issiq taomlar, keyin ichimliklar. menyu ni va issiqTaomlar ni chiqaring — asl massiv o'zgarmaganini ko'ring.

Yechim
js
const issiqTaomlar = ["Osh", "Lag'mon"];
const ichimliklar = ["Choy", "Kompot"];

const menyu = ["Non", ...issiqTaomlar, ...ichimliklar];
console.log(menyu);
console.log(issiqTaomlar);

Konsolda:

text
[ 'Non', 'Osh', "Lag'mon", 'Choy', 'Kompot' ]
[ 'Osh', "Lag'mon" ]

Node "Lag'mon" ni qo'shtirnoq bilan chiqardi, chunki ichida apostrof bor. Asl issiqTaomlar o'zgarmadi — spread yangi massiv yasadi.

2-mashq (o'rta): Ilova sozlamalari

sozlamaYasa funksiyasini yozing. U foydalanuvchi tanlovi obyektini oladi va standart sozlamalar bilan birlashtirib qaytaradi. Foydalanuvchi tanlovi ustun bo'lsin.

js
const standart = { til: "uz", mavzu: "yorug'", bildirishnoma: true };

sozlamaYasa({ til: "ru" }) → { til: 'ru', mavzu: "yorug'", bildirishnoma: true }.

Bonus: sozlamaYasa() (argumentsiz) ham ishlasin. Ishora: obyekt spread'da undefined xato bermaydi.

Yechim
js
const standart = { til: "uz", mavzu: "yorug'", bildirishnoma: true };

function sozlamaYasa(tanlov) {
  return { ...standart, ...tanlov };
}

console.log(sozlamaYasa({ til: "ru" }));
console.log(sozlamaYasa());

Konsolda:

text
{ til: 'ru', mavzu: "yorug'", bildirishnoma: true }
{ til: 'uz', mavzu: "yorug'", bildirishnoma: true }

standart birinchi yoyildi, tanlov keyin — shuning uchun til: "ru" ustun chiqdi. Argumentsiz chaqiruvda tanlov — undefined, obyekt spread esa uni jimgina o'tkazib yuboradi. standart obyekti o'zgarmaydi: har safar yangi obyekt qaytadi.

3-mashq (qiyin): O'rtacha baho

ortacha funksiyasini rest parametr bilan yozing. U istalgan sondagi bahoni olib, o'rtachasini qaytarsin. Baho berilmasa — 0 qaytarsin (nolga bo'lishdan saqlaning).

Keyin quyidagi massivning o'rtachasini spread bilan hisoblang:

js
const baholar = [5, 4, 5, 3];

Kutilgan natijalar: ortacha(5, 4) → 4.5, ortacha() → 0, ortacha(...baholar) → 4.25.

Yechim
js
function ortacha(...sonlar) {
  if (sonlar.length === 0) {
    return 0;
  }
  let summa = 0;
  for (const son of sonlar) {
    summa += son;
  }
  return summa / sonlar.length;
}

const baholar = [5, 4, 5, 3];

console.log(ortacha(5, 4)); // 4.5
console.log(ortacha()); // 0
console.log(ortacha(...baholar)); // 4.25

Parametrdagi ...sonlar — rest: argumentlarni massivga yig'adi. Chaqiruvdagi ...baholar — spread: massivni alohida argumentlarga yoyadi. Funksiya ichida esa ular yana massivga yig'iladi. Erta qaytish bilan bo'sh holatni boshida hal qildik — aks holda 0 / 0 NaN berardi.

12. Real ishda

  • React va holat (state). React'da ma'lumotni joyida o'zgartirish taqiqlangan. Yangilash doim spread bilan yangi nusxa yasash orqali bo'ladi: { ...foydalanuvchi, ism: "Ali" }, [...royxat, yangiElement]. Buni kursning React qismida har kuni yozasiz.
  • Sozlamalarni birlashtirish. Kutubxonalar standart sozlamalarni sizning tanlovingiz bilan aynan { ...standart, ...tanlov } naqshida birlashtiradi.
  • Server kodi. Foydalanuvchi yuborgan ma'lumotni bazadagi yozuv bilan birlashtirish, javobga qo'shimcha maydon qo'shish — hammasi obyekt spread bilan.
  • Yordamchi funksiyalar. log(...xabarlar) kabi istalgan sondagi argument oladigan funksiyalar rest bilan yoziladi.

Intervyuda deyarli har doim so'rashadi: "Spread va rest farqi nima?". Qisqa javob: "Belgi bir xil. Spread qiymat joyida turib, massiv yoki obyektni yoyadi. Rest o'zgaruvchi yoki parametr joyida turib, qiymatlarni yig'adi." Keyingi savol ko'pincha: "Spread chuqur nusxa oladimi?" — Yo'q, sayoz.

Xulosa

  • ... qiymat joyida — spread (yoyadi), o'zgaruvchi/parametr joyida — rest (yig'adi).
  • Massiv: [...a] — nusxa, [...a, ...b] — birlashtirish, [x, ...a] — aslini o'zgartirmay qo'shish.
  • Obyekt: { ...o } — nusxa, { ...a, ...b } — birlashtirish, bir xil kalitda keyingisi ustun. { ...o, narx: 1 } — bitta xususiyatni yangilash.
  • f(...massiv) — massivni alohida argumentlarga yoyadi: Math.max(...narxlar). [...matn] — satrni belgilarga, emoji'ni buzmasdan.
  • function f(...args) — haqiqiy massiv, arguments ning zamonaviy o'rni. Faqat bitta va oxirida.
  • Spread nusxasi sayoz: ichma-ich obyektlar umumiy qoladi.

Keyingi dars: Parametrda destructuring va options obyekti — destructuring va default qiymatlarni funksiya parametrida ishlatib, ko'p parametrli funksiyalarni tartibga keltiramiz.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript spread va rest operatori: uch nuqta ... ning ikki vazifasi — IlmHamroh