Ob'ektlar havolalar orqali nusxalanishi(Object references and copying)
Obyektlar va primitivlar o'rtasidagi asosiy farqlardan biri shundaki, obyektlar "havola orqali" saqlanadi va nusxalanadi, primitiv qiymatlar esa satrlar, raqamlar, booleanlar va hokazolar "to'liq qiymat sifatida" har doim nusxalanadi.
Ob'ektlar havolalar orqali nusxalanishi
Obyektlar va primitivlar o'rtasidagi asosiy farqlardan biri shundaki, obyektlar "havola orqali" saqlanadi va nusxalanadi, primitiv qiymatlar esa: satrlar, raqamlar, bo'leanslar va hokazolar "to'liq qiymat sifatida" har doim nusxalanadi.
Bu qiymat nusxalanganda nima sodir bo'lishini bilib olish orqali oson tushuniladi.
Keling, satr kabi bir primitivdan boshlaymiz.
Mana, biz xabarni satrga nusxaladik:
Natijada, bizda ikkita mustaqil o'zgaruvchi mavjud bo'ladi, ularning har biri "Hello!" satrini saqlaydi.
Bu juda oddiy natija, to'g'rimi?
Ob'ektlar bunga o'xshamaydi.
Ob'ektga tayinlangan o'zgaruvchi ob'ektning o'zini emas, balki uning "xotiradagi manzili"ni - boshqacha qilib aytganda, unga "havola" saqlaydi.
Keling, bunday o'zgaruvchining misoliga qaraylik:
Mana, bu qanday qilib xotirada saqlanadi:
Ob'ekt xotiraning biror joyida saqlanadi (rasmning o'ng tomonida), foydalanuvchi o'zgaruvchisi esa unga "havola" saqlaydi.
Biz foydalanuvchi kabi ob'ekt o'zgaruvchisini ob'ektning manzili yozilgan qog'oz varag'i sifatida tasavvur qilishimiz mumkin.
Ob'ekt bilan harakatlar bajarganimizda, masalan, user.name
xususiyatini olganda, JavaScript dvigateli manzilda nima borligini tekshiradi va haqiqiy ob'ekt ustida operatsiyani bajaradi.
Mana, nima uchun bu muhim.
Ob'ekt o'zgaruvchisi nusxalanganda, havola nusxalanadi, ammo ob'ektning o'zi dublikat qilinmaydi.
Misol uchun:
Endi bizda ikkita o'zgaruvchi mavjud, ularning har biri bir xil ob'ektga havola saqlaydi:
Ko'rib turganingizdek, bitta ob'ekt bor, ammo endi unga ikkita o'zgaruvchi havola qiladi.
Biz ob'ektga kirish va uning mazmunini o'zgartirish uchun har qanday o'zgaruvchidan foydalanishimiz mumkin:
Bu go'yo ikkita kalitli shkaf bor va ulardan birini (admin) ishlatib, ichiga kirib o'zgartirishlar kiritamiz. Keyin, agar boshqa kalitni (user) ishlatadigan bo'lsak, biz hali ham bir xil shkafni ochamiz va o'zgartirilgan mazmunga kirishimiz mumkin.
Havola orqali taqqoslash
Ikki ob'ekt faqat ular bir xil ob'ekt bo'lsa teng bo'ladi.
Masalan, bu yerda a
va b
bir xil ob'ektga havola qiladi, shuning uchun ular teng:
Va bu yerda ikkita mustaqil ob'ekt teng emas, garchi ular bir-biriga o'xshasa ham (ikkalasi ham bo'sh):
Ob'ektlar bilan obj1 > obj2
yoki primitiv bilan taqqoslash obj == 5
kabi taqqoslashlarda ob'ektlar primitivlarga aylantiriladi. Bunday taqqoslashlar juda kam hollarda kerak bo'ladi, chunki odatda ular dasturlashdagi xatolik natijasida paydo bo'ladi.
Const ob'ektlarini o'zgartirish mumkin
Ob'ektlarni havola sifatida saqlashning muhim yon ta'siri shundaki, const
deb e'lon qilingan ob'ektni o'zgartirish mumkin.
Masalan:
(*): chiziq xatoga olib keladi deb o'ylash mumkin, lekin u xato bermaydi. user
qiymati doimiy, u har doim bir xil ob'ektga havola qilishi kerak, ammo ob'ektning xususiyatlari o'zgarishi mumkin.
Boshqacha qilib aytganda, const user
faqat user = ...
ga butunlay o'rnatishga harakat qilganda xatolik beradi.
Agar biz chindan ham doimiy ob'ekt xususiyatlarini yaratishimiz kerak bo'lsa, bu ham mumkin, ammo butunlay boshqa usullardan foydalangan holda. Bu haqda "Property flags and descriptors" bo'limida gaplashamiz.
Klonlash va birlashtirish, Object.assign
Shunday qilib, ob'ekt o'zgaruvchisini nusxalash yana bir havolani yaratadi.
Ammo agar biz ob'ektni nusxalashimiz kerak bo'lsa-chi?
Biz yangi ob'ekt yaratishimiz va mavjud ob'ektning tuzilishini takrorlashimiz mumkin, uni primitiv darajada nusxalash orqali.
Bu kabi:
Biz Object.assign
metodidan ham foydalanishimiz mumkin.
Sintaksis:
Birinchi argument dest
- bu maqsadli ob'ekt.
Keyingi argumentlar esa manba ob'ektlarning ro'yxatidir.
U barcha manba ob'ektlarining xususiyatlarini maqsadli dest
ob'ektiga nusxalaydi, so'ngra natijani qaytaradi.
Misol uchun, bizda user
ob'ekti mavjud, keling, unga bir nechta ruxsatlarni qo'shamiz:
Agar nusxalangan xususiyat nomi allaqachon mavjud bo'lsa, u ustiga yoziladi:
Biz Object.assign
metodidan oddiy ob'ektni klonlash uchun ham foydalanishimiz mumkin:
Bu yerda u user
ob'ektining barcha xususiyatlarini bo'sh ob'ektga nusxalaydi va uni qaytaradi.
Shuningdek, klonlashning boshqa usullari ham mavjud, masalan, tarqalish sintaksisidan foydalanish clone = {...user}
, bu keyinchalik qo'llanma davomida o'rganiladi.
Ichki klonlash
Hozirgacha biz user
ning barcha xususiyatlari primitiv deb taxmin qildik. Ammo xususiyatlar boshqa ob'ektlarga havola bo'lishi mumkin.
Bu kabi:
Endi user.sizes
- bu o'zining height
va width
xususiyatlariga ega bo'lgan ob'ekt. user
ning boshqa xususiyatlari kabi, u havola orqali nusxalanadi.
Misol uchun:
Shuning uchun, chuqur klonlashni amalga oshirish uchun rekursiya kerak bo'ladi. Manzillarni saqlaydigan user
o'zgarmasligi kerak.
Chuqur klonlash uchun rekursiyani qo'llashni biz keyingi safar ko'rib chiqamiz.
Xulosa
- Primitivlar bilan o'zgaruvchiga boshqa primitivni tayinlash o'zgaruvchining yangi nusxasini yaratadi.
- Obyektlar boshqa o'zgaruvchilarga nusxalanganda, o'zgaruvchilar ob'ektning xotiradagi manzilini o'z ichiga oladi, shuning uchun ular bir xil ob'ektga kirish imkoniyatiga ega.
- Ob'ektlar o'rtasidagi taqqoslash ularning havolalarini solishtiradi. Ikkala ob'ekt ham bir xil bo'lsa faqat ular teng hisoblanadi.
const
ob'ektlari, ular o'zlari o'zgarmas bo'lsa ham, o'z xususiyatlarini o'zgartirishi mumkin.- Ob'ektlarni klonlash uchun
Object.assign
yordamida yangi ob'ekt yaratib, mavjud obyektning barcha xususiyatlarini nusxalash mumkin. Rekursiya yordamida chuqur nusxalash mumkin.
Bu Object.assign
yoki tarqalish sintaksisida foydalanishni o'z ichiga olgan bo'lsa, har doim obyektning chuqur klonlanishini unutmang.