O‘zgaruvchilarni e’lon qilish va qiymat tayinlash
Kompyuter dasturlashining eng fundamental texnikalaridan biri bu qiymatlarni ifodalash uchun nomlar — yoki identifikatorlardan — foydalanishdir. Nomni qiymatga bog‘lash bizga o‘sha qiymatga murojaat qilish va uni biz yozayotgan dasturlarda ishlatish imkonini beradi. Biz bu ishni qilganimizda, odatda, o‘zgaruvchiga qiymat tayinlayapmiz deymiz. "O‘zgaruvchi" atamasi yangi qiymatlar tayinlanishi mumkinligini anglatadi: ya’ni, o‘zgaruvchi bilan bog‘langan qiymat dasturimiz ishlashi davomida o‘zgarishi mumkin. Agar biz biror nomga qiymatni doimiy ravishda biriktirsak, u holda bu nomni o‘zgaruvchi emas, konstanta deb ataymiz.
JavaScript dasturida o‘zgaruvchi yoki konstantani ishlatishdan oldin, siz uni e’lon qilishingiz kerak. ES6 va undan keyingi versiyalarda bu let
va const
kalit so‘zlari bilan amalga oshiriladi, ularni keyinroq tushuntiramiz. ES6'dan oldin o‘zgaruvchilar var
bilan e’lon qilinardi, bu ancha o‘ziga xosroq va ushbu mavzuning keyingi qismida tushuntiriladi.
let
va const
bilan e’lon qilish
Zamonaviy JavaScript'da (ES6 va undan keyin) o‘zgaruvchilar let
kalit so‘zi bilan e’lon qilinadi, masalan:
Siz bitta let
ko‘rsatmasida bir nechta o‘zgaruvchini ham e’lon qilishingiz mumkin:
Iloji boricha, o‘zgaruvchilarni e’lon qilayotganda ularga boshlang‘ich qiymat berish yaxshi dasturlash amaliyoti hisoblanadi:
Agar siz let
ko‘rsatmasi bilan o‘zgaruvchiga boshlang‘ich qiymat bermasangiz, o‘zgaruvchi e’lon qilinadi, lekin kodingiz unga qiymat tayinlamaguncha uning qiymati undefined
bo‘lib qoladi.
O‘zgaruvchi o‘rniga konstanta e’lon qilish uchun let
o‘rniga const
'dan foydalaning. const
xuddi let
kabi ishlaydi, faqat siz konstantani e’lon qilish paytida uni initsializatsiya qilishingiz (boshlang‘ich qiymat berishingiz) shart:
Nomidan ko‘rinib turganidek, konstantalarning qiymatini o‘zgartirib bo‘lmaydi va bunga qilingan har qanday urinish TypeError
xatoligiga sabab bo‘ladi.
Konstantalarni o‘zgaruvchilardan farqlash uchun ularni H0
yoki HTTP_NOT_FOUND
kabi butunlay bosh harflar bilan yozilgan nomlar yordamida e’lon qilish keng tarqalgan (lekin universal bo‘lmagan) qoidadir.
const
'ni qachon ishlatish kerak?
const
kalit so‘zidan foydalanish bo‘yicha ikki xil qarash mavjud. Birinchi yondashuv — const
'ni faqat yuqorida ko‘rsatilgan fizik konstantalar, dastur versiyasi raqamlari yoki fayl turlarini aniqlash uchun ishlatiladigan baytlar ketma-ketligi kabi fundamental jihatdan o‘zgarmaydigan qiymatlar uchun ishlatish.
Ikkinchi yondashuv esa dasturlarimizdagi "o‘zgaruvchi" deb ataladigan ko‘plab qiymatlar aslida dastur ishlashi davomida hech qachon o‘zgarmasligini tan oladi. Bu yondashuvda biz hamma narsani const
bilan e’lon qilamiz va agar qiymatning haqiqatan ham o‘zgarishiga ruxsat berishni istasak, e’lonni let
'ga o‘zgartiramiz. Bu biz o‘zgartirishni niyat qilmagan o‘zgaruvchilarga tasodifiy o‘zgartirish kiritishning oldini olib, xatoliklarni kamaytirishga yordam berishi mumkin.
Xulosa qilib aytganda, birinchi yondashuvda biz const
'ni faqat o‘zgarishi mumkin bo‘lmagan qiymatlar uchun ishlatamiz. Ikkinchisida esa, biz const
'ni shunchaki o‘zgarmaydigan har qanday qiymat uchun ishlatamiz. Men o‘z kodimda birinchi yondashuvni afzal ko‘raman.
5-bobda biz JavaScript'dagi for
, for/in
va for/of
sikl ko‘rsatmalarini o‘rganamiz. Bu sikllarning har biri siklning har bir iteratsiyasida yangi qiymat tayinlanadigan sikl o‘zgaruvchisiga ega. JavaScript sikl o‘zgaruvchisini sikl sintaksisining bir qismi sifatida e’lon qilishga imkon beradi va bu let
'ni ishlatishning yana bir keng tarqalgan usulidir:
Bu g‘alati tuyulishi mumkin, lekin siz for/in
va for/of
sikllarining "o‘zgaruvchilarini" e’lon qilish uchun const
'dan ham foydalanishingiz mumkin, agar sikl tanasi unga yangi qiymat qayta tayinlamasa. Bu holda, const
e’loni shunchaki qiymatning bitta sikl iteratsiyasi davomida o‘zgarmas ekanligini bildiradi:
O‘zgaruvchi va konstantalarning ko‘rinish doirasi (scope
)
O‘zgaruvchining ko‘rinish doirasi (scope
) — bu dasturingiz manba kodining u aniqlangan qismidir. let
va const
bilan e’lon qilingan o‘zgaruvchilar va konstantalar blokli ko‘rinish doirasiga (block scoped
) ega. Bu shuni anglatadiki, ular faqat let
yoki const
ko‘rsatmasi joylashgan kod bloki ichidagina aniqlangan bo‘ladi. JavaScript'da klass va funksiya ta’riflari, shuningdek, if/else
ko‘rsatmalari, while
sikllari, for
sikllari va hokazolarning tanasi blok hisoblanadi. Qisqacha aytganda, agar o‘zgaruvchi yoki konstanta jingalak qavslar to‘plami ichida e’lon qilinsa, o‘sha jingalak qavslar bu o‘zgaruvchi yoki konstanta aniqlangan kod hududini chegaralaydi (garchi, albatta, o‘zgaruvchini e’lon qiladigan let
yoki const
ko‘rsatmasidan oldin bajariladigan kod qatorlaridan unga murojaat qilish mumkin bo‘lmasa ham). for
, for/in
yoki for/of
siklining bir qismi sifatida e’lon qilingan o‘zgaruvchi va konstantalar, texnik jihatdan jingalak qavslardan tashqarida paydo bo‘lsa-da, ularning ko‘rinish doirasi sikl tanasi hisoblanadi.
Agar e’lon eng yuqori darajada, har qanday kod blokidan tashqarida paydo bo‘lsa, biz uni global o‘zgaruvchi yoki konstanta deymiz va u global ko‘rinish doirasiga ega bo‘ladi. Node'da va klient tomonidagi JavaScript modullarida (10-bobga qarang), global o‘zgaruvchining ko‘rinish doirasi u aniqlangan fayl hisoblanadi. An’anaviy klient tomonidagi JavaScript'da esa, global o‘zgaruvchining ko‘rinish doirasi u aniqlangan HTML hujjati hisoblanadi. Ya’ni: agar bitta <script>
global o‘zgaruvchi yoki konstantani e’lon qilsa, bu o‘zgaruvchi yoki konstanta o‘sha hujjatdagi barcha <script>
elementlarida (yoki hech bo‘lmaganda, let
yoki const
ko‘rsatmasi bajarilgandan keyin ishga tushadigan barcha skriptlarda) aniqlangan bo‘ladi.
Takroriy e’lonlar
Bir ko‘rinish doirasi (scope
) ichida bir xil nomni bir nechta let
yoki const
e’lonlari bilan ishlatish sintaktik xatodir. Ichki joylashgan ko‘rinish doirasida xuddi shu nom bilan yangi o‘zgaruvchi e’lon qilish esa mumkin (garchi bu amaliyotni qilmaslik ma’qul bo‘lsa ham):
E’lonlar va tiplar
Agar siz C yoki Java kabi statik tipli tillarga o‘rgangan bo‘lsangiz, o‘zgaruvchilarni e’lon qilishning asosiy maqsadi o‘zgaruvchiga tayinlanishi mumkin bo‘lgan qiymatlarning tipini ko‘rsatish deb o‘ylashingiz mumkin. Lekin, ko‘rib turganingizdek, JavaScript'ning o‘zgaruvchi e’lonlarida hech qanday tip biriktirilmaydi.1 JavaScript o‘zgaruvchisi har qanday tipdagi qiymatni saqlashi mumkin. Masalan, JavaScript'da bir o‘zgaruvchiga avval son, keyinroq esa satr tayinlash mutlaqo mumkin (lekin odatda bu yomon dasturlash uslubi hisoblanadi):
var
bilan o‘zgaruvchilarni e’lon qilish
JavaScript'ning ES6'dan oldingi versiyalarida o‘zgaruvchini e’lon qilishning yagona yo‘li var
kalit so‘zi edi va konstantalarni e’lon qilishning imkoni yo‘q edi. var
'ning sintaksisi xuddi let
'ning sintaksisi kabi:
Garchi var
va let
bir xil sintaksisga ega bo‘lsa-da, ularning ishlashida muhim farqlar mavjud:
-
var
bilan e’lon qilingan o‘zgaruvchilar blokli ko‘rinish doirasiga (block scope
ga) ega emas. Buning o‘rniga, ular o‘zlari joylashgan funksiya tanasi ichida qanchalik chuqur joylashganidan qat’i nazar, o‘sha funksiya ko‘rinish doirasiga (function scope
ga) ega bo‘ladi. -
Agar siz
var
'ni funksiya tanasidan tashqarida ishlatsangiz, u global o‘zgaruvchi e’lon qiladi. Lekinvar
bilan e’lon qilingan global o‘zgaruvchilarlet
bilan e’lon qilingan globallardan muhim bir jihati bilan farq qiladi.var
bilan e’lon qilingan globallar global obyektning (§3.7) xossalari sifatida implementatsiya qilinadi. Global obyektgaglobalThis
orqali murojaat qilish mumkin. Shunday qilib, agar siz funksiyadan tashqaridavar x = 2;
deb yozsangiz, bu xuddiglobalThis.x = 2;
deb yozganingizdek bo‘ladi. Biroq shuni yodda tutingki, bu o‘xshatish mukammal emas: globalvar
e’lonlari bilan yaratilgan xossalarnidelete
operatori (§4.13.4) bilan o‘chirib bo‘lmaydi.let
vaconst
bilan e’lon qilingan global o‘zgaruvchilar va konstantalar esa global obyektning xossalari emas. -
let
bilan e’lon qilingan o‘zgaruvchilardan farqli o‘laroq, bir xil o‘zgaruvchinivar
bilan bir necha marta e’lon qilish mumkin. Chunkivar
o‘zgaruvchilari blokli emas, funksiya ko‘rinish doirasiga ega bo‘lgani uchun, bunday qayta e’lon qilish amaliyoti aslida keng tarqalgan.i
o‘zgaruvchisi ko‘pincha butun sonli qiymatlar uchun, ayniqsa,for
sikllarining indeks o‘zgaruvchisi sifatida ishlatiladi. Bir nechtafor
sikliga ega funksiyada, har biriningfor(var i = 0; ...
bilan boshlanishi odatiy holdir.var
bu o‘zgaruvchilarni sikl tanasi bilan cheklamagani uchun, bu sikllarning har biri bir xil o‘zgaruvchini (zararsiz) qayta e’lon qiladi va qayta initsializatsiya qiladi. -
var
e’lonlarining eng g’ayrioddiy xususiyatlaridan biri "ko‘tarilish" (hoisting
) deb nomlanadi. O‘zgaruvchivar
bilan e’lon qilinganda, e’lonning o‘zi u joylashgan funksiyaning eng yuqorisiga "ko‘tariladi". O‘zgaruvchining initsializatsiyasi siz yozgan joyda qoladi, lekin o‘zgaruvchining ta’rifi funksiyaning tepasiga ko‘chadi. Shunday qilib,var
bilan e’lon qilingan o‘zgaruvchilarni ular joylashgan funksiyaning istalgan yerida xatosiz ishlatish mumkin. Agar initsializatsiya kodi hali ishga tushmagan bo‘lsa, o‘zgaruvchining qiymatiundefined
bo‘lishi mumkin, lekin siz o‘zgaruvchini initsializatsiya qilinishidan oldin ishlatsangiz, xatolikka duch kelmaysiz. (Bu xatoliklar manbai bo‘lishi mumkin valet
buni tuzatishi mumkin muhim kamchiliklardan biridir: agar siz o‘zgaruvchinilet
bilan e’lon qilsangiz, lekin unilet
ko‘rsatmasi ishga tushishidan oldin ishlatishga harakat qilsangiz, shunchakiundefined
qiymatini ko‘rish o‘rniga, haqiqiy xatolikka duch kelasiz.)
E’lon qilinmagan o‘zgaruvchilardan foydalanish
Qat’iy rejimda (strict mode
, §5.6.3), agar siz e’lon qilinmagan o‘zgaruvchidan foydalanishga harakat qilsangiz, kodingizni ishga tushirganingizda ReferenceError
xatoligiga duch kelasiz. Biroq qat’iy rejimsiz, agar siz let
, const
yoki var
bilan e’lon qilinmagan nomga qiymat tayinlasangiz, yakunda yangi global o‘zgaruvchi yaratib qo‘yasiz. Kodingiz funksiyalar va bloklar ichida qanchalik chuqur joylashganidan qat’i nazar, bu o‘zgaruvchi global bo‘ladi. Bu esa, deyarli hech qachon siz xohlagan natija emas, xatoliklarga moyil va qat’iy rejimdan foydalanish uchun eng asosli sabablardan biridir!
Bu tasodifiy usulda yaratilgan global o‘zgaruvchilar var
bilan e’lon qilingan global o‘zgaruvchilarga o‘xshaydi: ular global obyektning xossalarini aniqlaydi. Lekin to‘g‘ri var
e’lonlari bilan aniqlangan xossalardan farqli o‘laroq, bu xossalarni delete
operatori (§4.13.4) yordamida o‘chirib yuborish mumkin.
Destrukturizatsiya orqali tayinlash
ES6 destrukturizatsiya (destructuring
), ya’ni tuzilmani qismlarga ajratish orqali tayinlash deb nomlanuvchi murakkab e’lon qilish va qiymat tayinlash sintaksisini implementatsiya qiladi. Destrukturizatsiya orqali tayinlashda, tenglik belgisining o‘ng tomonidagi qiymat massiv yoki obyekt ("tuzilmali" qiymat) bo‘ladi, chap tomon esa massiv va obyekt literallari sintaksisiga taqlid qiluvchi sintaksis yordamida bir yoki bir nechta o‘zgaruvchi nomlarini ko‘rsatadi. Bu amal sodir bo‘lganda, o‘ng tomondagi qiymatdan bir yoki bir nechta qiymatlar "ajratib olinadi" ("destrukturizatsiya qilinadi") va chap tomonda nomlangan o‘zgaruvchilarga saqlanadi.
Destrukturizatsiya, ehtimol, eng ko‘p const
, let
yoki var
e’lon qilish ko‘rsatmasining bir qismi sifatida o‘zgaruvchilarni initsializatsiya qilish uchun ishlatiladi, lekin uni oddiy tayinlash ifodalarida ham (allaqachon e’lon qilingan o‘zgaruvchilar bilan) bajarish mumkin. Va §8.3.5-bo‘limda ko‘rib chiqadiganimizdek, destrukturizatsiyadan funksiya parametrlarini aniqlashda ham foydalanish mumkin.
Massiv destrukturizatsiyasi
Quyida qiymatlar massividan foydalanadigan oddiy destrukturizatsiya misollari keltirilgan:
Destrukturizatsiya qiymatlar massivini qaytaradigan funksiyalar bilan ishlashni qanchalik osonlashtirishiga e’tibor bering:
Biz o‘zgaruvchilar va konstantalarni JavaScript'ning turli for
sikllarining bir qismi sifatida e’lon qilish mumkinligini ko‘rdik. Bu kontekstda o‘zgaruvchilarni destrukturizatsiya qilishdan ham foydalanish mumkin. Quyida obyektning barcha xossalarining nom/qiymat juftliklari bo‘ylab aylanib chiqadigan va bu juftliklarni ikki elementli massivlardan alohida o‘zgaruvchilarga aylantirish uchun destrukturizatsiyadan foydalanadigan kod keltirilgan:
Destrukturizatsiya orqali tayinlashda chap tomondagi o‘zgaruvchilar soni o‘ng tomondagi massiv elementlari soniga mos kelishi shart emas. Chap tomondagi ortiqcha o‘zgaruvchilarga undefined
qiymati beriladi, o‘ng tomondagi ortiqcha qiymatlar esa e’tiborsiz qoldiriladi. Chap tomondagi o‘zgaruvchilar ro‘yxati o‘ng tomondagi ba’zi qiymatlarni o‘tkazib yuborish uchun unda qo‘shimcha vergullar ham bo'lishi mumkin:
Massivni destrukturizatsiya qilayotganda barcha ishlatilmagan yoki qolgan qiymatlarni bitta o‘zgaruvchiga yig‘ib olmoqchi bo‘lsangiz, chap tomondagi oxirgi o‘zgaruvchi nomidan oldin uchta nuqta (...
) ishlating:
Uchta nuqtaning bu tarzda ishlatilishini §8.3.2-bo‘limda yana ko‘ramiz, u yerda ular funksiyaning qolgan barcha argumentlarini bitta massivga yig‘ish kerakligini bildirish uchun ishlatiladi.
Destrukturizatsiya orqali tayinlashni ichma-ich joylashgan massivlar bilan ham ishlatish mumkin. Bunday holda, tayinlashning chap tomoni ichma-ich joylashgan massiv literaliga o‘xshashi kerak:
Massiv destrukturizatsiyasining kuchli bir xususiyati shundaki, u aslida massiv bo'lishni talab qilmaydi! Siz tayinlashning o‘ng tomonida har qanday iteratsiya qilinadigan (iterable
) obyektni (12-bob) ishlatishingiz mumkin; for/of
sikli (§5.4.4) bilan ishlatilishi mumkin bo‘lgan har qanday obyektni destrukturizatsiya qilish ham mumkin:
Obyekt destrukturizatsiyasi
Destrukturizatsiya orqali tayinlashni o‘ng tomondagi qiymat obyekt bo‘lganda ham amalga oshirish mumkin. Bunday holda, tayinlashning chap tomoni obyekt literaliga o‘xshaydi: jingalak qavslar ichida vergul bilan ajratilgan o‘zgaruvchi nomlari ro‘yxati:
Keyingi misol Math
obyektining global funksiyalarini o‘zgaruvchilarga ko‘chirib oladi, bu ko‘p trigonometrik hisob-kitoblarni bajaradigan kodni soddalashtirishi mumkin:
Bu yerdagi kodda e’tibor bering, Math
obyekti alohida o‘zgaruvchilarga destrukturizatsiya qilingan uchta xossadan tashqari ko‘plab boshqa xossalarga ham ega. Nomlari ko‘rsatilmagan xossalar shunchaki e’tiborsiz qoldiriladi. Agar bu tayinlashning chap tomonida nomi Math
'ning xossasi bo‘lmagan o‘zgaruvchi bo‘lganida, bu o‘zgaruvchiga shunchaki undefined
qiymati tayinlanar edi.
Ushbu obyekt destrukturizatsiyasi misollarining har birida biz destrukturizatsiya qilinayotgan obyektning xossa nomlariga mos keladigan o‘zgaruvchi nomlarini tanladik. Bu sintaksisni sodda va tushunarli saqlaydi, lekin bu majburiy emas. Obyekt destrukturizatsiyasi tayinlashining chap tomonidagi identifikatorlarning har biri ikki nuqta bilan ajratilgan identifikatorlar juftligi ham bo‘lishi mumkin. Bunda birinchisi qiymati tayinlanishi kerak bo‘lgan xossaning nomi, ikkinchisi esa qiymat tayinlanadigan o‘zgaruvchining nomi bo‘ladi:
Shaxsan men o‘zgaruvchi nomlari va xossa nomlari bir xil bo‘lmaganda, obyekt destrukturizatsiyasi sintaksisi foydali bo‘lish uchun juda murakkablashib ketadi deb hisoblayman va bunday hollarda qisqa yozuvdan qochishga harakat qilaman. Agar siz undan foydalanishni tanlasangiz, yodda tutingki, xossa nomlari har doim ikki nuqtaning chap tomonida bo‘ladi — ham obyekt literallarida, ham obyekt destrukturizatsiyasi tayinlashining chap tomonida.
Destrukturizatsiya orqali tayinlash ichma-ich joylashgan obyektlar, obyektlar massivlari yoki massivlar obyektlari bilan ishlatilganda yanada murakkablashadi, lekin bunga ruxsat etilgan:
Yoki obyektlar massivini destrukturizatsiya qilish o‘rniga, biz massivlar obyektini destrukturizatsiya qilishimiz mumkin:
Bunga o‘xshash murakkab destrukturizatsiya sintaksisini yozish ham, o‘qish ham qiyin bo‘lishi mumkin va siz shunchaki let x1 = points.p1[0];
kabi an’anaviy kod bilan tayinlashlarni aniq yozib chiqqaningiz ma’qulroq bo‘lishi mumkin.
Murakkab destrukturizatsiyani tushunish
Agar siz murakkab destrukturizatsiya orqali tayinlashlardan foydalanadigan kod bilan ishlayotgan bo‘lsangiz, murakkab holatlarni tushunishga yordam beradigan foydali bir qonuniyat mavjud. Avval oddiy (bitta qiymatli) tayinlash haqida o‘ylang. Tayinlash bajarilgandan so‘ng, siz tayinlashning chap tomonidagi o‘zgaruvchi nomini olib, uni kodingizda ifoda sifatida ishlatishingiz mumkin va u o‘ziga tayinlangan qiymatni qaytaradi.
Xuddi shu narsa destrukturizatsiya orqali tayinlash uchun ham o‘rinlidir. Destrukturizatsiya orqali tayinlashning chap tomoni massiv literali yoki obyekt literaliga (§6.2.1 va §6.10) o‘xshaydi. Tayinlash bajarilgandan so‘ng, chap tomon haqiqatan ham kodingizning boshqa joyida haqiqiy massiv literali yoki obyekt literali sifatida ishlay oladi. Siz destrukturizatsiya orqali tayinlashni to‘g‘ri yozganingizni chap tomonni boshqa bir tayinlash ifodasining o‘ng tomonida ishlatib ko‘rish orqali tekshirishingiz mumkin:
-
TypeScript va Flow (§17.8) kabi JavaScript kengaytmalari
let x: number = 0;
kabi sintaksis bilan o‘zgaruvchilarni e’lon qilishda tiplarni ko‘rsatish imkonini beradi. ↩