Funktsiyalar armiyasi
Quyidagi kod shooters
massivini yaratadi.
Har bir funktsiya o’z raqamini chiqarishi kerak. Lekin nimadir noto’g’ri…
function makeArmy() {
let shooters = [];
let i = 0;
while (i < 10) {
let shooter = function() { // shooter funktsiyasini yaratish,
alert( i ); // o'z raqamini ko'rsatishi kerak
};
shooters.push(shooter); // uni massivga qo'shish
i++;
}
// ...va shooterlar massivini qaytarish
return shooters;
}
let army = makeArmy();
// barcha shooterlar o'z raqamlari 0, 1, 2, 3... o'rniga 10 ni ko'rsatadi
army[0](); // 0-raqamli shooterdan 10
army[1](); // 1-raqamli shooterdan 10
army[2](); // 10 ...va hokazo.
Nima uchun barcha shooterlar bir xil qiymatni ko’rsatadi?
Kod mo’ljallangandek ishlashi uchun uni tuzating.
makeArmy
ichida aynan nima sodir bo’lishini ko’rib chiqaylik, va yechim aniq bo’lib qoladi.
-
U bo’sh
shooters
massivini yaratadi:let shooters = [];
-
Sikl orqali
shooters.push(function)
yordamida uni funktsiyalar bilan to’ldiradi.Har bir element funktsiya, shuning uchun natijada olingan massiv shunday ko’rinadi:
shooters = [ function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, function () { alert(i); }, ];
-
Massiv funktsiyadan qaytariladi.
Keyin, keyinroq, istalgan a’zoga chaqiruv, masalan
army[5]()
massivdanarmy[5]
elementini oladi (bu funktsiya) va uni chaqiradi.Endi nega bunday barcha funktsiyalar bir xil qiymatni, ya’ni
10
ni ko’rsatadi?Bu
shooter
funktsiyalari ichida mahalliyi
o’zgaruvchisi yo’qligi sababli. Bunday funktsiya chaqirilganda, ui
ni o’zining tashqi leksik muhitidan oladi.U holda
i
ning qiymati nima bo’ladi?Agar manbaga qarasak:
function makeArmy() { ... let i = 0; while (i < 10) { let shooter = function() { // shooter funktsiyasi alert( i ); // o'z raqamini ko'rsatishi kerak }; shooters.push(shooter); // funktsiyani massivga qo'shish i++; } ... }
Ko’ramizki, barcha
shooter
funktsiyalarmakeArmy()
funktsiyasining leksik muhitida yaratilgan. Lekinarmy[5]()
chaqirilganda,makeArmy
allaqachon o’z ishini tugatgan vai
ning oxirgi qiymati10
(while
i=10
da to’xtaydi).Natijada, barcha
shooter
funktsiyalar tashqi leksik muhitdan bir xil qiymatni oladi va bu oxirgi qiymat, ya’nii=10
.Yuqorida ko’rib turganingizdek,
while {...}
blokining har bir iteratsiyasida yangi leksik muhit yaratiladi. Shuning uchun, buni tuzatish uchuni
ning qiymatiniwhile {...}
bloki ichidagi o’zgaruvchiga nusxalashimiz mumkin:function makeArmy() { let shooters = []; let i = 0; while (i < 10) { let j = i; let shooter = function() { // shooter funktsiyasi alert( j ); // o'z raqamini ko'rsatishi kerak }; shooters.push(shooter); i++; } return shooters; } let army = makeArmy(); // Endi kod to'g'ri ishlaydi army[0](); // 0 army[5](); // 5
Bu yerda
let j = i
“iteratsiya-mahalliy”j
o’zgaruvchisini e’lon qiladi vai
ni unga nusxalaydi. Primitivlar “qiymat bo’yicha” nusxalanadi, shuning uchun biz aslida joriy sikl iteratsiyasiga tegishlii
ning mustaqil nusxasini olamiz.Shooterlar to’g’ri ishlaydi, chunki
i
ning qiymati endi bir oz yaqinroq joyda yashaydi.makeArmy()
Leksik muhitida emas, balki joriy sikl iteratsiyasiga mos keladigan Leksik muhitda:Agar boshidayoq
for
ishlatganimizda ham bunday muammoning oldini olish mumkin edi:function makeArmy() { let shooters = []; for(let i = 0; i < 10; i++) { let shooter = function() { // shooter funktsiyasi alert( i ); // o'z raqamini ko'rsatishi kerak }; shooters.push(shooter); } return shooters; } let army = makeArmy(); army[0](); // 0 army[5](); // 5
Bu mohiyatan bir xil, chunki
for
har bir iteratsiyada o’ziningi
o’zgaruvchisi bilan yangi leksik muhit yaratadi. Shuning uchun har bir iteratsiyada yaratilganshooter
aynan shu iteratsiyadagi o’zi
siga havola qiladi.
Endi, siz buni o’qishga shuncha harakat qilganingizdan so’ng va oxirgi retsept shuncha oddiy – shunchaki for
dan foydalaning, siz hayron bo’lishingiz mumkin – bunga arziydimi?
Albatta, agar siz savolga osonlik bilan javob bera olsangiz, yechimni o’qimagan bo’lardingiz. Shuning uchun, umid qilamanki, bu vazifa sizga narsalarni biroz yaxshiroq tushunishga yordam bergan bo’lishi kerak.
Bundan tashqari, haqiqatan ham for
dan ko’ra while
ni afzal ko’radigan holatlar va bunday muammolar haqiqiy bo’lgan boshqa stsenariylar mavjud.