IlmHamroh
JavaScript Full-stack/8-qism. JavaScript asoslari56/61-dars18 daqiqa
Mundarija (37)

JavaScript havola semantikasi: nega nusxa o'zgarib ketdi?

Qisqacha: JavaScript'da primitiv (son, satr, boolean) o'zgaruvchida qiymatning o'zi bo'lib saqlanadi. Obyekt va massiv esa xotiraning alohida joyida turadi, o'zgaruvchida faqat unga havola saqlanadi. Shuning uchun const b = a obyektni nusxalamaydi: ikki o'zgaruvchi bitta obyektga qaraydi va biri o'zgartirsa, ikkinchisi ham o'zgarganini ko'radi. === ham obyekt ichini emas, havolani taqqoslaydi.

Bu darsda

  • Primitiv va obyekt xotirada qanday saqlanishini jadval bilan tushuntira olasiz.
  • Qayta tayinlash (b = ...) va o'zgartirish (b.x = ...) farqini bilasiz.
  • Funksiyaga obyekt berilganda asl obyekt nega o'zgarishini tushunasiz va buning oldini olasiz.
  • Obyektlarni === bilan solishtirish nima uchun false berishini tushuntira olasiz.
  • Obyekt va massivning haqiqiy nusxasini ola olasiz.

Oldin bilishingiz kerak: Ma'lumot turlari xaritasi, Pure funksiya va side effect, Element qo'shish va olib tashlash, Obyekt bo'ylab yurish.

1. Nega bu kerak?

Oldingi darsda Object.entries va Object.fromEntries bilan obyektning o'zgartirilgan nusxasini yasadik. O'shanda "asl obyekt o'zgarmadi — nega bu muhimligini keyingi darsda ko'ramiz" degan edik. Mana o'sha dars.

Tasavvur qiling: siz onlayn do'kon uchun admin panel yozyapsiz. Admin mahsulotni tahrirlash oynasini ochadi. Siz "asl nusxaga tegmasin, admin nusxada ishlasin" deb shunday yozasiz:

js
const mahsulot = { nom: "Choynak", narx: 120000 };

const tahrir = mahsulot; // "nusxa" oldik
tahrir.narx = 99000; // admin narxni o'zgartirdi

// Admin "Bekor qilish" tugmasini bosdi...
console.log(mahsulot.narx); // 99000

Admin bekor qildi, lekin do'kondagi narx baribir 99 000 bo'lib qoldi! Xato xabari yo'q, qizil yozuv yo'q. Ertaga mijozlar choynakni arzon narxda sotib olishadi.

Ma'lumot turlari darsida bu hodisa bilan qisqacha tanishgan edik. Endi uni tubigacha tushunamiz: xotirada aslida nima bo'ladi, qayerda xavf bor va haqiqiy nusxa qanday olinadi.

2. Xotirada nima sodir bo'ladi?

2.1 Primitiv: qiymatning o'zi qutida

let va const darsida o'zgaruvchini yorliqli quti deb tasavvur qilgan edik. Primitiv qiymatlar uchun bu rasm aynan to'g'ri: qutida qiymatning o'zi yotadi.

js
let narx = 5000;
let yangiNarx = narx;
yangiNarx = 7000;

console.log(narx); // 5000
console.log(yangiNarx); // 7000

let yangiNarx = narx qatori 5000 sonining nusxasini yangi qutiga soldi. Xotirada shunday ko'rinadi:

O'zgaruvchi Qutida nima bor
narx 5000
yangiNarx 5000 → keyin 7000

Ikki quti — ikki alohida son. Birini o'zgartirish ikkinchisiga ta'sir qilmaydi. Buni qiymat bo'yicha nusxalash (copy by value) deb ataganmiz. Satr, boolean, null, undefined — barcha primitivlar shunday ishlaydi.

2.2 Obyekt: qutida faqat manzil

Obyekt boshqacha saqlanadi. U katta bo'lishi mumkin, o'sib-kichrayishi mumkin. Shuning uchun JavaScript obyektni xotiraning alohida joyiga qo'yadi. O'zgaruvchi qutisiga esa faqat o'sha joyning manzili yoziladi.

Bu manzil havola (reference) deb ataladi. Havola — "obyekt qayerda turibdi" degan ko'rsatkich.

js
const mahsulot = { nom: "Choynak", narx: 120000 };

Xotirada (manzilni #1 deb belgilaymiz — haqiqiy manzilni JavaScript o'zi tanlaydi va sizga ko'rsatmaydi):

O'zgaruvchi Qutida nima bor
mahsulot havola → #1
Manzil Obyekt
#1 { nom: "Choynak", narx: 120000 }

2.3 = havolani nusxalaydi

Endi 1-bo'limdagi xatoga qaytamiz. const tahrir = mahsulot qatori nima qiladi? U mahsulot qutisidagi narsani nusxalaydi. Qutida esa obyekt emas, havola bor edi. Demak havola nusxalandi:

O'zgaruvchi Qutida nima bor
mahsulot havola → #1
tahrir havola → #1

Ikki quti, lekin ikkalasida bitta manzil. Obyekt esa xotirada hamon bitta. Sxemada:

text
mahsulot ──┐
           ├──►  #1: { nom: "Choynak", narx: 120000 }
tahrir ────┘

tahrir.narx = 99000 qatori "#1 manzilidagi obyektning narxini o'zgartir" degani. mahsulot.narx ni o'qiganda ham JavaScript #1 ga boradi — va o'zgargan narxni topadi.

Ma'lumot turlari darsidagi o'xshatishni eslang: Telegram guruhiga havola. Siz do'stingizga guruh havolasini yubordingiz. Endi ikkalangiz bitta guruhga kirasiz. Do'stingiz guruhga xabar yozsa, siz ham ko'rasiz — chunki guruh bitta, havola ikkita.

Buni havola bo'yicha nusxalash (copy by reference) deyiladi.

2.4 Massiv ham obyekt

Massiv obyektning bir turi, shuning uchun u ham havola bilan saqlanadi:

js
const xaridlar = ["non", "sut"];
const royxat = xaridlar;

royxat.push("tuxum");

console.log(xaridlar); // [ 'non', 'sut', 'tuxum' ]

Biz faqat royxat ga qo'shdik, lekin xaridlar ham o'zgardi. Element qo'shish darsida ko'rgan push massivni joyida o'zgartiradi — va bu joy ikki o'zgaruvchi uchun ham bitta.

Tur Nima saqlanadi b = a dan keyin
Primitiv Qiymatning o'zi Ikki mustaqil qiymat
Obyekt, massiv Havola (manzil) Bitta obyektga ikki havola

Tekshirib ko'ring: Konsolda nima chiqadi?

js
const a = { ball: 50 };
const b = a;
b.ball = b.ball + 10;
console.log(a.ball);
Javob

60. b = a obyektni emas, havolani nusxaladi. a ham, b ham bitta obyektga qaraydi. b.ball ni o'zgartirish — o'sha yagona obyektni o'zgartirish.

3. Qayta tayinlash va o'zgartirish: ikki xil amal

Bu darsning eng muhim bo'limi. Havola bilan ishlaganda ikki xil amal bor va ular butunlay boshqa natija beradi.

3.1 O'zgartirish (mutatsiya): b.x = ...

Nuqta yoki kvadrat qavs orqali ichini o'zgartirsangiz, siz havola ko'rsatgan obyektni o'zgartirasiz. Bu mutatsiya — massiv darsidan tanish so'z. Obyekt bitta bo'lgani uchun, unga qaragan hamma o'zgaruvchi o'zgarishni ko'radi. push, pop, delete ham mutatsiya.

3.2 Qayta tayinlash: b = ...

O'zgaruvchiga butunlay yangi qiymat bersangiz, siz faqat shu qutidagi havolani almashtirasiz. Obyektga tegmaysiz:

js
const asl = { shahar: "Toshkent" };
let nusxa = asl;

nusxa = { shahar: "Buxoro" }; // yangi obyekt, yangi havola

console.log(asl.shahar); // Toshkent
console.log(nusxa.shahar); // Buxoro

Qayta tayinlashdan keyin xotirada endi ikki alohida obyekt bor, har biriga bittadan havola:

text
asl ─────►  #1: { shahar: "Toshkent" }
nusxa ───►  #2: { shahar: "Buxoro" }

nusxa endi boshqa obyektga qaraydi. asl esa eski joyida — unga hech narsa bo'lmadi.

Telegram o'xshatishida: do'stingiz eski guruhdan chiqib, boshqa guruh havolasini ochdi. Endi u yozgan xabarlar siz turgan guruhga tushmaydi.

Amal Misol Nimani o'zgartiradi Boshqa havolalarga ta'siri
O'zgartirish b.narx = 5 Obyektning ichini Bor
Qayta tayinlash b = { narx: 5 } Faqat b qutisini Yo'q

O'zingiz to'ldiring: let x = { son: 1 }; let y = x; y.son = 2; dan keyin x.son — [:2]. let x = { son: 1 }; let y = x; y = { son: 2 }; dan keyin esa x.son — [:1].

3.3 const obyektni muzlatmaydi

Endi const ning nega obyekt ichini o'zgartirishga yo'l qo'yishi tushunarli bo'ladi. const qutini qotiradi: undagi havolani boshqasiga almashtirib bo'lmaydi. Havola ko'rsatgan obyektni esa qotirmaydi:

js
const mijoz = { ism: "Ali" };

mijoz.ism = "Vali"; // ✅ obyekt ichi — mumkin

console.log(mijoz.ism); // Vali

Qayta tayinlashga urinsangiz esa:

js
const mijoz = { ism: "Ali" };

mijoz = { ism: "Vali" };
text
TypeError: Assignment to constant variable.

Tarjimasi: "o'zgarmas (const) o'zgaruvchiga qiymat berish". const quti ichidagi havolani almashtirishni taqiqladi. Lekin 3.1 dagi mutatsiyani taqiqlamaydi.

Maslahat: Obyekt ichini ham haqiqatan "muzlatish" kerak bo'lsa, Object.freeze bor. Uni Obyektni himoyalash darsida o'rganamiz.

Tekshirib ko'ring: const ballar = [80, 90]; dan keyin ballar.push(100) ishlaydimi? ballar = [100] chi?

Javob

ballar.push(100) ishlaydi — bu mutatsiya, massiv ichini o'zgartiradi, const bunga qarshi emas. ballar = [100] esa TypeError: Assignment to constant variable. beradi — bu qayta tayinlash, const aynan shuni taqiqlaydi.

4. Funksiyaga obyekt berish

4.1 Primitiv parametr — asliga tegmaydi

Parametrlar darsida ko'rganingizdek, funksiya chaqirilganda argument parametrga yoziladi. Aslida bu ham = bilan nusxalashning o'zi:

js
function oshir(son) {
  son = son + 1;
  return son;
}

let hisob = 10;
oshir(hisob);

console.log(hisob); // 10

son ga 10 ning nusxasi yozildi. Funksiya o'z nusxasini o'zgartirdi, hisob esa 10 ligicha qoldi.

4.2 Obyekt parametr — asli o'zgaradi

Endi obyekt beramiz:

js
function chegirmaQil(buyurtma) {
  buyurtma.narx = buyurtma.narx * 0.9;
}

const meningBuyurtmam = { taom: "osh", narx: 40000 };
chegirmaQil(meningBuyurtmam);

console.log(meningBuyurtmam.narx); // 36000

buyurtma parametriga obyektning havolasi yozildi. Funksiya ichidagi buyurtma va tashqaridagi meningBuyurtmam — bitta obyektga qaraydi:

text
meningBuyurtmam ──┐
                  ├──►  #1: { taom: "osh", narx: 40000 }
buyurtma ─────────┘     (funksiya ichida)

Funksiya #1 ning narxini o'zgartirdi — tashqarida ham narx o'zgardi. Massiv bersangiz ham shunday: funksiya ichidagi push tashqaridagi massivga element qo'shadi.

4.3 Parametrni qayta tayinlash — tashqariga ta'sir qilmaydi

3-bo'limdagi qoida funksiyada ham ishlaydi:

js
function almashtir(buyurtma) {
  buyurtma = { taom: "lag'mon", narx: 30000 };
}

const meningBuyurtmam = { taom: "osh", narx: 40000 };
almashtir(meningBuyurtmam);

console.log(meningBuyurtmam.taom); // osh

buyurtma = {...} faqat funksiya ichidagi qutini boshqa obyektga yo'naltirdi. Tashqaridagi meningBuyurtmam eski obyektga qarab turibdi.

Maslahat: Intervyuda ko'p so'raladi: "JavaScript'da obyekt funksiyaga qiymat bo'yicha beriladimi yoki havola bo'yicha?" Aniq javob: JavaScript har doim qiymatni nusxalaydi. Faqat obyekt uchun bu qiymat — havolaning o'zi. Shuning uchun ichini o'zgartirsangiz — tashqarida ko'rinadi 4.2-bob, parametrni qayta tayinlasangiz — ko'rinmaydi 4.3-bob. Inglizcha bu "call by sharing" deb ham ataladi.

4.4 Bu — side effect

Pure funksiya darsida side effect turlari orasida "massiv yoki obyektni o'zgartirish" ham bor edi. Endi nega xavfli ekanini ko'rdingiz: chegirmaQil hech narsa qaytarmaydi. Lekin u chaqiruvchining obyektini jimgina o'zgartirdi. Kodni o'qigan odam chegirmaQil(meningBuyurtmam) qatoridan buni sezmasligi mumkin.

Toza yo'l — asliga tegmasdan, yangi obyekt qaytarish:

js
function chegirmaQil(buyurtma) {
  return {
    taom: buyurtma.taom,
    narx: buyurtma.narx * 0.9,
  };
}

const meningBuyurtmam = { taom: "osh", narx: 40000 };
const chegirmali = chegirmaQil(meningBuyurtmam);

console.log(meningBuyurtmam.narx); // 40000
console.log(chegirmali.narx); // 36000

Endi funksiya toza: kirgan obyektni faqat o'qiydi, natijani yangi obyektda qaytaradi. Asl buyurtma ham, yangisi ham qo'lingizda.

Tekshirib ko'ring: function tozala(r) { r.push("tayyor"); } va const vazifalar = []; bo'lsa, tozala(vazifalar) dan keyin vazifalar.length nechchi?

Javob

1. Funksiyaga massivning havolasi berildi. r.push — mutatsiya, u o'sha yagona massivga element qo'shdi. Shuning uchun tashqaridagi vazifalar da ham bitta element bor.

5. === havolani taqqoslaydi

5.1 Bir xil ko'rinish — boshqa obyekt

js
const a = { ism: "Ali" };
const b = { ism: "Ali" };
const c = a;

console.log(a === b); // false
console.log(a === c); // true

a va b ichi bir xil, lekin === false berdi. Sababi: har bir { ... } yozuvi xotirada yangi obyekt yaratadi. a — #1 ga, b — #2 ga qaraydi. === esa obyekt ichini emas, havolalarni taqqoslaydi: "ikkalasi bitta obyektmi?"

a va c esa bitta obyektga qaraydi — shuning uchun true.

Hayotdan o'xshatish: egizaklar. Ular bir xil kiyinishi, bir xil ko'rinishi mumkin. Lekin baribir ikki xil odam. === "bir xil ko'rinadimi?" deb emas, "bu o'sha odammi?" deb so'raydi.

Tenglik darsidagi Object.is ham obyektlar uchun xuddi shunday ishlaydi. Massivlar ham: [] === [] — false.

5.2 includes ham havolani qidiradi

Massivda obyekt qidirishda bu ayniqsa chalg'itadi:

js
const savat = [{ nom: "olma" }, { nom: "nok" }];

console.log(savat.includes({ nom: "olma" })); // false

Savatda olma bor, lekin includes topmadi. U === bilan solishtiradi, biz esa unga yangi obyekt berdik. Bunday yangi obyekt massivda yo'q.

To'g'ri yo'l — xususiyat bo'yicha qidirish. Buni massivda qidirish darsidagi some yoki find qiladi:

js
const savat = [{ nom: "olma" }, { nom: "nok" }];

const olmaBor = savat.some((m) => m.nom === "olma");

console.log(olmaBor); // true

Bu yerda m.nom === "olma" — ikki satr solishtiriladi. Satr primitiv, shuning uchun qiymat bo'yicha taqqoslanadi.

Tekshirib ko'ring: const x = [1, 2]; bo'lsa, x === x va x === [1, 2] nima beradi?

Javob

true va false. x === x — bitta havola o'zi bilan solishtirildi. [1, 2] esa yangi massiv yaratadi, u boshqa manzilda turadi.

6. Kutilmagan o'zgarishlar: uch tuzoq

6.1 Bitta obyektni qayta-qayta qo'shish

Jadval uchun uch qator yasamoqchimiz:

js
const qator = {};
const jadval = [];

for (let i = 1; i <= 3; i++) {
  qator.raqam = i;
  jadval.push(qator);
}

console.log(jadval); // [ { raqam: 3 }, { raqam: 3 }, { raqam: 3 } ]

1, 2, 3 kutgandik — hammasi 3! Sikl ichida biz yangi obyekt yaratmadik. Har safar o'sha bitta qator obyektining havolasini qo'shdik. Massivda uchta havola, obyekt esa bitta — oxirgi qiymati 3.

Tuzatish: obyektni sikl ichida yarating. Har aylanishda { ... } yangi obyekt beradi:

js
const jadval = [];

for (let i = 1; i <= 3; i++) {
  jadval.push({ raqam: i });
}

console.log(jadval); // [ { raqam: 1 }, { raqam: 2 }, { raqam: 3 } ]

6.2 find natijasi — nusxa emas

js
const talabalar = [
  { ism: "Ali", ball: 70 },
  { ism: "Malika", ball: 90 },
];

const topilgan = talabalar.find((t) => t.ism === "Ali");
topilgan.ball = 100;

console.log(talabalar[0].ball); // 100

find topgan obyektning havolasini qaytaradi. topilgan va talabalar[0] — bitta obyekt. Ba'zan aynan shu kerak (ro'yxatdagi talabaning balini yangilash). Lekin "topib olib, alohida ishlayman" deb o'ylasangiz — asl ro'yxat buziladi.

6.3 Massiv nusxasi, lekin ichidagi obyektlar umumiy

Kesish darsida massiv nusxasini slice() bilan olishni ko'rgansiz. Nusxa haqiqatan yangi massiv:

js
const talabalar = [
  { ism: "Ali", ball: 70 },
  { ism: "Malika", ball: 90 },
];

const nusxa = talabalar.slice();
nusxa.push({ ism: "Jasur", ball: 60 });
nusxa[0].ball = 100;

console.log(talabalar.length); // 2
console.log(talabalar[0].ball); // 100

push faqat nusxaga ta'sir qildi — uzunlik 2 ligicha qoldi. Lekin nusxa[0].ball = 100 asl massivdagi Alini ham o'zgartirdi! Sababi: slice() massivni nusxaladi, lekin ichidagi obyektlarni emas. Yangi massiv ichida — eski obyektlarning havolalari.

O'zgaruvchi Massiv ichida nima bor
talabalar havola #1 (Ali), havola #2 (Malika)
nusxa havola #1 (Ali), havola #2 (Malika), havola #3 (Jasur)

Faqat birinchi qavat nusxalandi. Buni sayoz nusxa (shallow copy) deyiladi. Bu mavzuni Sayoz va chuqur nusxalash darsida to'liq o'rganamiz.

7. Haqiqiy nusxa qanday olinadi?

7.1 Massiv nusxasi

Massivning o'zini nusxalash uchun ikki tanish yo'l bor (kesish darsidan):

js
const xaridlar = ["non", "sut"];

const n1 = xaridlar.slice();
const n2 = [...xaridlar];

n1.push("tuxum");

console.log(xaridlar); // [ 'non', 'sut' ]
console.log(n1 === xaridlar); // false

[...xaridlar] — spread yozuvi: "massiv elementlarini yangi massivga yoy". Uni Spread va rest darsida batafsil o'rganamiz.

7.2 Obyekt nusxasi

Oldingi darsdagi entries → fromEntries naqshi aynan yangi obyekt yasaydi:

js
const asl = { nom: "Choynak", narx: 120000 };

const nusxa = Object.fromEntries(Object.entries(asl));
nusxa.narx = 99000;

console.log(asl.narx); // 120000
console.log(nusxa === asl); // false

Ishlaydi, lekin uzun. Real kodda buning uchun spread yozuvi ishlatiladi — { ...asl }. U obyektning barcha xususiyatlarini yangi obyektga "yoyadi". Yoniga o'zgargan xususiyatni ham qo'shish mumkin:

js
const asl = { nom: "Choynak", narx: 120000 };

const yangi = { ...asl, narx: 99000 };

console.log(asl); // { nom: 'Choynak', narx: 120000 }
console.log(yangi); // { nom: 'Choynak', narx: 99000 }

Hozircha bu yozuvni tanib qoling. U qanday ishlashini va qoidalarini Spread va rest darsida o'rganamiz. 1-bo'limdagi admin panel muammosi aynan shu bilan hal qilinadi: const tahrir = { ...mahsulot }.

7.3 Ichma-ich obyekt: sayoz nusxa yetmaydi

Spread ham, fromEntries ham, slice ham — sayoz nusxa. Ichma-ich obyekt bo'lsa, ichkisi umumiy qoladi:

js
const asl = { nom: "Choynak", tafsilot: { rang: "oq" } };

const nusxa = { ...asl };
nusxa.tafsilot.rang = "qora";

console.log(asl.tafsilot.rang); // qora

Barcha qavatlarni nusxalaydigan tayyor funksiya bor — structuredClone:

js
const asl = { nom: "Choynak", tafsilot: { rang: "oq" } };

const nusxa = structuredClone(asl);
nusxa.tafsilot.rang = "qora";

console.log(asl.tafsilot.rang); // oq

Bu chuqur nusxa (deep copy). Uning chegaralari va qachon ishlatish kerakligi — Sayoz va chuqur nusxalash darsida.

Nima kerak Usul Qaysi darsda
Massiv nusxasi arr.slice(), [...arr] Kesish va birlashtirish, Spread va rest
Obyekt nusxasi { ...obj } Spread va rest
Ichma-ich hammasi structuredClone(obj) Sayoz va chuqur nusxalash

8. Ko'p uchraydigan xatolar

8.1 = ni nusxa deb o'ylash

1-bo'limdagi const tahrir = mahsulot — eng ko'p uchraydigan xato. Obyekt yoki massivda = — bu ikkinchi nom, nusxa emas.

8.2 Obyektlarni === bilan solishtirish

js
const eski = { ism: "Ali", yosh: 20 };
const yangi = { ism: "Ali", yosh: 20 };

if (eski === yangi) {
  console.log("O'zgarish yo'q");
} else {
  console.log("Ma'lumot o'zgardi!");
}

Konsolda:

text
Ma'lumot o'zgardi!

Ichi bir xil, lekin kod "o'zgardi" dedi. Ikki xil obyektni ichidagi qiymatlar bo'yicha solishtirish uchun xususiyatlarni birma-bir tekshirish kerak (3-mashqda o'zingiz yozasiz).

8.3 Funksiya argumentini jimgina o'zgartirish

js
function teskariNavbat(nomlar) {
  nomlar.reverse();
  return nomlar;
}

const navbat = ["Ali", "Malika", "Jasur"];
const teskari = teskariNavbat(navbat);

console.log(navbat); // [ 'Jasur', 'Malika', 'Ali' ]

Funksiya faqat natija qaytaradi deb o'ylagandik. Lekin reverse mutatsiya qiladi — asl navbat ham teskari bo'lib qoldi. Tuzatish: avval nusxa oling — nomlar.slice().reverse().

9. Mashqlar

1-mashq (oson): Natijani oldindan ayting

Kodni ishga tushirmasdan, har bir console.log nima chiqarishini yozing. Keyin tekshiring.

js
let a = "choy";
let b = a;
b = "qahva";

const x = { ichimlik: "choy" };
const y = x;
y.ichimlik = "qahva";

console.log(a);
console.log(b);
console.log(x.ichimlik);
console.log(x === y);
Yechim

Konsolda:

text
choy
qahva
qahva
true

a — satr, primitiv: b = a qiymat nusxasini oldi, keyin b qayta tayinlandi. a o'zgarmadi. x esa obyekt: y = x havolani nusxaladi, y.ichimlik = ... — mutatsiya, shuning uchun x.ichimlik ham "qahva". x === y — true, chunki ikkalasi bitta obyektga qaraydi.

2-mashq (o'rta): Funksiyani toza qiling

Bu funksiya xodimga bonus qo'shadi, lekin asl obyektni o'zgartirib yuboradi:

js
function bonusQosh(xodim, summa) {
  xodim.oylik = xodim.oylik + summa;
  return xodim;
}

Uni shunday qayta yozingki, u asl obyektga tegmasin va yangi obyekt qaytarsin. So'ng const nodira = { ism: "Nodira", oylik: 5000000 }; bilan sinab ko'ring: nodira.oylik 5 000 000 ligicha qolsin, yangi obyektda esa 5 500 000 bo'lsin.

Ishora: 4.4-bo'limdagi chegirmaQil kabi — return { ism: ..., oylik: ... }. Xohlasangiz, 7.2 dagi { ...xodim, oylik: ... } yozuvini ham sinab ko'ring.

Yechim
js
function bonusQosh(xodim, summa) {
  return {
    ism: xodim.ism,
    oylik: xodim.oylik + summa,
  };
}

const nodira = { ism: "Nodira", oylik: 5000000 };
const yangi = bonusQosh(nodira, 500000);

console.log(nodira.oylik); // 5000000
console.log(yangi.oylik); // 5500000
console.log(nodira === yangi); // false

Funksiya xodim ni faqat o'qidi va natijani yangi obyektda qaytardi. Spread bilan: return { ...xodim, oylik: xodim.oylik + summa }; — bu variant boshqa xususiyatlarni (masalan, lavozim) ham ko'chiradi.

3-mashq (qiyin): Ichidagi qiymatlar bo'yicha solishtirish

tengmi(a, b) funksiyasini yozing. U ikki tekis obyektni (ichida boshqa obyekt yo'q) ichidagi qiymatlar bo'yicha solishtirsin:

  • kalitlar soni har xil bo'lsa — false;
  • a ning biror kaliti uchun a[kalit] !== b[kalit] bo'lsa — false;
  • aks holda — true.

Sinab ko'ring: { ism: "Ali", yosh: 20 } va { yosh: 20, ism: "Ali" } → true; { ism: "Ali" } va { ism: "Vali" } → false.

Ishora: kalitlar soni — oldingi darsdagi Object.keys(...).length. Kalitlar bo'ylab for...of bilan yuring va farq topilishi bilan erta qaytish bilan false qaytaring.

Yechim
js
function tengmi(a, b) {
  const aKalitlar = Object.keys(a);
  if (aKalitlar.length !== Object.keys(b).length) {
    return false;
  }
  for (const kalit of aKalitlar) {
    if (a[kalit] !== b[kalit]) {
      return false;
    }
  }
  return true;
}

const t1 = { ism: "Ali", yosh: 20 };
const t2 = { yosh: 20, ism: "Ali" };

console.log(t1 === t2); // false
console.log(tengmi(t1, t2)); // true
console.log(tengmi({ ism: "Ali" }, { ism: "Vali" })); // false
console.log(tengmi({ ism: "Ali" }, { ism: "Ali", yosh: 1 })); // false

=== havolalarni solishtirib false berdi, tengmi esa ichini solishtirib true berdi. Kalitlar tartibi muhim emas: biz a ning har kaliti bo'yicha b dan qiymat so'radik.

Kalitlar sonini tekshirmasak, oxirgi misol true berib qo'yardi. Bu funksiya sayoz: ichma-ich obyektlarni baribir havola bo'yicha solishtiradi.

10. Real ishda

  • React. React ekranni qachon yangilashni havolaga qarab hal qiladi. Obyektni joyida o'zgartirsangiz (user.ism = "Vali"), havola o'sha-o'sha qoladi va React o'zgarishni ko'rmaydi — ekran yangilanmaydi. Shuning uchun React'da har doim yangi obyekt yasaladi: { ...user, ism: "Vali" }. Bu boshlovchilarning React'dagi eng ko'p uchraydigan xatolaridan biri.
  • Server. Node.js serverida umumiy sozlama obyektini bitta so'rov ichida o'zgartirib qo'yish boshqa foydalanuvchilarning so'rovlariga ham ta'sir qiladi. Bunday xatoni topish soatlab vaqt oladi.

Intervyuda deyarli har doim so'raladi: "{} === {} nima beradi va nega?", "Obyekt funksiyaga qanday uzatiladi?", "Obyektni qanday nusxalaysiz?" Endi uchalasiga ham javob bera olasiz.

Maslahat: Havolasi qolmagan obyekt nima bo'ladi? JavaScript uni avtomatik ravishda xotiradan o'chiradi — bu ishni garbage collector ("axlat yig'uvchi") bajaradi. Bu qanday ishlashini Xotira boshqaruvi darsida o'rganamiz.

Xulosa

  • Primitiv o'zgaruvchida qiymatning o'zi saqlanadi; obyekt va massiv o'zgaruvchisida esa havola (manzil).
  • b = a obyektni emas, havolani nusxalaydi — ikki o'zgaruvchi bitta obyektga qaraydi.
  • b.x = ... (mutatsiya) umumiy obyektni o'zgartiradi; b = ... (qayta tayinlash) faqat b ni boshqa joyga yo'naltiradi.
  • Funksiyaga berilgan obyektni o'zgartirish — side effect; toza yo'l — yangi obyekt qaytarish.
  • === obyekt ichini emas, havolani taqqoslaydi: {} === {} — false.
  • const havolani qotiradi, obyekt ichini emas. Nusxa: slice(), [...arr], { ...obj }; ichma-ich uchun structuredClone.

Keyingi dars: Obyekt destructuring — obyektdan kerakli xususiyatlarni bitta qatorda alohida o'zgaruvchilarga ajratib olishni o'rganamiz.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript havola semantikasi: nega nusxa o'zgarib ketdi? — IlmHamroh