JavaScript — chuqur texnik intervyu
Full-stack dasturchi uchun eng ko'p so'raladigan JavaScript intervyu savollari. Bu — eng muhim mavzu: deyarli har bir frontend va Node.js suhbatida savollarning yarmi shu yerdan chiqadi. Har bir javob ta'rif mexanizm kod tuzoq follow-up tuzilishida berilgan, toki siz shu fayl bilan haqiqiy intervyudan bemalol o'ta olasiz.
Qanday foydalanish
- Avval savolni o'qing, javobni yopib o'zingiz aytishga urining, keyin tekshiring.
- Yodlamang — tushuning. Intervyuchi ta'rifdan keyin darrov "nega?" yoki "ichida qanday ishlaydi?" deb so'raydi. Shuning uchun har savolda Follow-up berilgan.
- Darajalar: Junior · Middle · Senior.
- Kod misollarni ovoz chiqarib tushuntirib bering — intervyu bilimni gapirib bera olishdir.
Maslahat: Har bir tuzoq () savolini alohida yodda tuting. Aynan shu savollarda ko'p nomzod "yiqiladi", va aynan shular sizni ajratib turadi.
1-BO'LIM: O'zgaruvchilar, scope va hoisting
S: var, let va const orasidagi farq nima? (Junior)
J: Ta'rif. Uchalasi ham o'zgaruvchi e'lon qiladi, lekin scope, qayta e'lon qilish va hoisting xatti-harakati bilan farqlanadi.
Mexanizm.
var— function-scoped (funksiya doirasida), qayta e'lon qilinadi, hoisting'daundefinedbilan ko'tariladi.let— block-scoped ({}doirasida), qayta e'lon qilib bo'lmaydi, lekin qiymatini o'zgartirsa bo'ladi. TDZ'ga tushadi.const— block-scoped, qiymatini qayta biriktirib (reassign) bo'lmaydi. TDZ'ga tushadi. Lekin obyekt/massiv ichini o'zgartirsa bo'ladi (chunki reference o'zgarmaydi).
function test() {
if (true) {
var a = 1;
let b = 2;
const c = 3;
}
console.log(a); // 1 — var blokdan chiqib ketadi
// console.log(b); // ReferenceError — let blokda qoladi
}
const user = { name: "Ali" };
user.name = "Vali"; // ruxsat — obyekt ichi
// user = {}; // TypeError — reference o'zgarishi mumkin emas Tuzoq. const "o'zgarmas qiymat" degani emas — u faqat bindingni (o'zgaruvchi qiymat bog'lanishini) qotiradi. Obyekt/massiv ichi bemalol o'zgaradi. To'liq qotirish uchun Object.freeze() kerak.
Follow-up. "TDZ nima?" · "Nega bugungi kunda var ishlatilmaydi?" · "const arr = []; arr.push(1) xato beradimi?" (yo'q).
S: Hoisting nima va u qanday ishlaydi? (Middle)
J: Ta'rif. Hoisting — JS'da e'lonlar (declarations) o'z scope'ining yuqorisiga ko'tarilgandek ishlashi. Aslida kod jismonan ko'chmaydi.
Mexanizm. JS kodni ikki bosqichda bajaradi:
- Creation (compile) fazasi — engine scope'ni skanerlab, barcha
varva funksiya e'lonlarini xotiraga yozadi.var—undefinedbilan, funksiya deklaratsiyasi — to'liq tanasi bilan.let/constham ko'tariladi, lekin initialize qilinmaydi (TDZ). - Execution fazasi — kod satrma-satr bajariladi, qiymatlar biriktiriladi.
console.log(x); // undefined (var ko'tarildi, qiymat yo'q)
var x = 5;
foo(); // "salom" — funksiya deklaratsiyasi to'liq ko'tariladi
function foo() { console.log("salom"); }
bar(); // TypeError: bar is not a function
var bar = function () {}; // faqat `bar` (undefined) ko'tariladi Tuzoq. Funksiya deklaratsiyasi to'liq hoisting bo'ladi, funksiya ifodasi (var bar = function(){}) esa faqat o'zgaruvchi sifatida undefined bo'lib ko'tariladi — chaqirsangiz TypeError.
Follow-up. "let hoisting bo'ladimi?" (ha, lekin TDZ'da) · "Nega arrow function chaqirilganda ham TypeError bo'ladi?" · "Compile va execution fazalarini tushuntiring."
S: Temporal Dead Zone (TDZ) nima? (Senior)
J: Ta'rif. TDZ — let/const o'zgaruvchi e'lon qilingan joyigacha bo'lgan "o'lik zona"; bu oraliqda unga murojaat qilish ReferenceError beradi.
Mexanizm. let/const ham scope boshida xotiraga ko'tariladi, lekin "uninitialized" holatida turadi. E'lon satriga yetguncha ular TDZ ichida bo'ladi. Engine bu o'zgaruvchiga har qanday murojaatni bloklaydi — bu varning "jimgina undefined" xatti-harakatidan farqli, aniq xato beradi va bug'larni erta ushlaydi.
{
// shu yerdan TDZ boshlandi
// console.log(name); // ReferenceError: Cannot access 'name' before initialization
let name = "Laylo"; // TDZ shu yerda tugadi
console.log(name); // "Laylo"
} Tuzoq. typeof odatda xavfsiz — lekin TDZ'dagi o'zgaruvchiga typeof ham ReferenceError beradi:
console.log(typeof y); // ReferenceError (TDZ)
let y = 10;
console.log(typeof z); // "undefined" (umuman e'lon qilinmagan) Follow-up. "TDZ nima uchun foydali?" (xatolarni erta ushlaydi) · "var bilan bu muammo bo'lmaydimi?" · "TDZ qachon boshlanadi va tugaydi?"
S: Scope nima? Lexical scope-chi? (Middle)
J: Ta'rif. Scope — o'zgaruvchining ko'rinish (murojaat qilinadigan) hududi. JS'da 3 xil: global, function, block scope. Lexical (statik) scope — funksiya qayerda yozilgani (chaqirilgani emas) uning tashqi o'zgaruvchilarga kirishini belgilaydi.
Mexanizm. Har bir funksiya yaratilganda o'zining scope chainiga ega bo'ladi: ichki funksiya tashqi funksiyaning, u esa global scope'ning o'zgaruvchilariga qatlamma-qatlam kira oladi. Engine o'zgaruvchini avval o'z scope'idan, topmasa yuqoriga qarab (chain bo'ylab) qidiradi.
const global = "G";
function tashqi() {
const t = "T";
function ichki() {
const i = "I";
console.log(global, t, i); // "G T I" — hammasiga kiradi
}
ichki();
}
tashqi();Tuzoq. Lexical scope yozilgan joyga bog'liq, chaqirilgan joyga emas. Funksiyani boshqa yerdan chaqirsangiz ham u o'zi yozilgan muhitdagi o'zgaruvchilarni ko'radi (bu — closure asosi).
Follow-up. "Scope chain nima?" · "Dynamic scope bilan farqi?" · "Bu closure bilan qanday bog'liq?"
2-BO'LIM: Closure
S: Closure nima? Amaliy misol bilan tushuntiring. (Middle)
J: Ta'rif. Closure — funksiya o'zi yaratilgan lexical muhitni "eslab qolishi"; tashqi funksiya tugagandan keyin ham uning o'zgaruvchilariga kira oladigan ichki funksiya.
Mexanizm. Ichki funksiya tashqi funksiyaning o'zgaruvchisiga murojaat qilsa, engine bu o'zgaruvchini garbage collector'dan saqlab qoladi — chunki unga hali havola bor. Ichki funksiya "yopilib" (close over) o'zgaruvchi ustidan reference ushlaydi. Har chaqiruvda alohida, mustaqil muhit yaratiladi.
function hisoblagich() {
let count = 0; // "yashirin" holat
return function () {
count++; // tashqi o'zgaruvchini eslaydi
return count;
};
}
const inc = hisoblagich();
console.log(inc()); // 1
console.log(inc()); // 2
console.log(inc()); // 3 — count saqlanib qoladi
const inc2 = hisoblagich();
console.log(inc2()); // 1 — mustaqil muhitAmaliy foyda: private o'zgaruvchilar (data encapsulation), factory funksiyalar, once/memoization, debounce/throttle, React hooks (useState closure ustida qurilgan).
Tuzoq. Closure o'zgaruvchining qiymatini emas, o'zini (referencesini) ushlaydi. Shuning uchun var bilan loop ichida closure yaratganda hammasi bir xil oxirgi qiymatni ko'radi (pastdagi setTimeout savoliga qarang).
Follow-up. "Closure xotira sizib chiqishiga (memory leak) sabab bo'ladimi?" · "Private o'zgaruvchini closure bilan qanday yasaysiz?" · "React useState closure'ga qanday tayanadi?"
S: Quyidagi kod nima chiqaradi va nega? (Senior — klassik tuzoq)
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}J: Javob: 3 3 3.
Mexanizm. var function-scoped — butun loop bo'yicha bitta i o'zgaruvchisi bor. setTimeout callback'lari asinxron — ular loop tugagandan keyin (i=3 bo'lgach) ishga tushadi. Uch callback ham bir xil iga (closure orqali) havola qiladi, va o'sha paytda i allaqachon 3.
Yechim 1 — let ishlating: let har iteratsiyada yangi binding yaratadi, shuning uchun har callback o'z nusxasini ko'radi.
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 0 1 2
}Yechim 2 — IIFE bilan qiymatni "qamab olish":
for (var i = 0; i < 3; i++) {
(function (j) {
setTimeout(() => console.log(j), 100); // 0 1 2
})(i);
} Tuzoq. Ko'pchilik 0 1 2 deb javob beradi. Sir — varning yagona bindingi + asinxronlik. Bu savol closure + scope + event loop'ni bir vaqtda tekshiradi.
Follow-up. "let ichkarida aynan nima o'zgaradi?" · "IIFE nega ishlaydi?" · "Bu real loyihada qanday bug'ga olib keladi?"
3-BO'LIM: this va bog'lanish
S: this nima? U qanday aniqlanadi? (Middle)
J: Ta'rif. this — funksiya qanday chaqirilganiga qarab aniqlanadigan maxsus ko'rsatkich (call-site'ga bog'liq, yozilgan joyga emas — arrow'dan tashqari).
Mexanizm — chaqiruv qoidalari (ustunlik tartibida):
newbilanthis= yangi yaratilgan obyekt.call/apply/bindbilanthis= siz bergan obyekt (explicit binding).- Metod sifatida
obj.f()this=obj(nuqtadan chapdagi). - Oddiy chaqiruv
f()this=undefined(strict mode) yokiglobalThis(sloppy mode). - Arrow function o'zining
thisi yo'q, tashqi (lexical) scopedan oladi.
const obj = {
name: "Aziz",
oddiy() { return this.name; },
strelka: () => this?.name,
};
console.log(obj.oddiy()); // "Aziz" — metod chaqiruvi
console.log(obj.strelka()); // undefined — arrow tashqi this'ni oldi
const f = obj.oddiy;
console.log(f()); // undefined (strict) — nuqtasiz chaqiruv, kontekst yo'qoldi Tuzoq. Metodni o'zgaruvchiga oldirsangiz (const f = obj.oddiy) this yo'qoladi — chunki call-site endi f(), nuqtasiz. Bu callback'larda tez-tez uchraydi (setTimeout(obj.oddiy) ishlamaydi).
Follow-up. "Arrow'da thisni bind bilan o'zgartirib bo'ladimi?" (yo'q) · "new thisni qanday o'rnatadi?" · "Callback'da this yo'qolishini qanday tuzatasiz?"
S: call, apply va bind orasidagi farq nima? (Middle)
J: Ta'rif. Uchalasi ham funksiyaning thisini qo'lda o'rnatadi (explicit binding), lekin argument berish va chaqirish usuli bilan farqlanadi.
Mexanizm.
call(thisArg, a, b)—thisni o'rnatib, funksiyani darrov chaqiradi, argumentlar vergul bilan.apply(thisArg, [a, b])— xuddicall, lekin argumentlar massivda.bind(thisArg, a)— chaqirmaydi,thisi qotirilgan yangi funksiya qaytaradi (keyinroq chaqirasiz).
function salom(shahar, mamlakat) {
return `${this.ism}, ${shahar}, ${mamlakat}`;
}
const p = { ism: "Nodira" };
console.log(salom.call(p, "Toshkent", "UZ")); // darrov
console.log(salom.apply(p, ["Toshkent", "UZ"])); // massiv bilan
const bog'langan = salom.bind(p, "Toshkent");
console.log(bog'langan("UZ")); // keyinroq chaqirildiXotira uchun: Call = Comma (vergul), Apply = Array (massiv), Bind = Bog'lab keyinroq.
Tuzoq. bind yangi funksiya qaytaradi — asl funksiyani o'zgartirmaydi. Va bir marta bind qilingan funksiyani qayta bind qilib bo'lmaydi (ikkinchi bind e'tiborga olinmaydi).
Follow-up. "bindni qo'lda qanday yozasiz?" · "Partial application nima?" · "React'da metodni nega konstruktorda bind qilishardi?"
S: Arrow function va oddiy function orasidagi farqlarni sanang. (Senior)
J: Ta'rif. Arrow function — qisqartirilgan sintaksis, lekin bir nechta muhim xatti-harakat farqlari bilan.
Farqlar:
this— arrow'ning o'zthisi yo'q, lexical (tashqi) scope'dan oladi. Oddiy funksiyadathischaqiruvga bog'liq.arguments— arrow'da yo'q (tashqidan oladi), oddiy'da bor.new— arrow konstruktor bo'la olmaydi (new arrow()TypeError).prototype— arrow'daprototypepropertysi yo'q.- hoisting — arrow (ifoda) hoisting bo'lmaydi; funksiya deklaratsiyasi bo'ladi.
const obj = {
items: [1, 2, 3],
ism: "Ro'yxat",
chop() {
// arrow tashqi `this`ni (obj) oladi — to'g'ri ishlaydi
this.items.forEach((x) => console.log(this.ism, x));
},
};
obj.chop(); // "Ro'yxat 1", "Ro'yxat 2", "Ro'yxat 3" Tuzoq. Obyekt metodini arrow qilib yozmang — this obyektga emas, tashqi scope'ga ishora qiladi:
const bad = { ism: "X", get() { return this.ism; } }; //
const worse = { ism: "X", get: () => this.ism }; // this — obyekt emas Follow-up. "Qachon arrow, qachon oddiy funksiya?" (callback arrow; metod/konstruktor oddiy) · "arguments o'rniga arrow'da nima?" (rest ...args) · "Nega arrow konstruktor bo'la olmaydi?"
4-BO'LIM: Prototype va meros (inheritance)
S: Prototypal inheritance nima? U qanday ishlaydi? (Middle)
J: Ta'rif. JS'da meros prototype zanjiri (prototype chain) orqali amalga oshadi: har bir obyekt boshqa obyektga (o'z prototypesiga) yashirin havolaga ega, va topilmagan propertylar shu zanjir bo'ylab qidiriladi.
Mexanizm. Obyektdan obj.x so'ralganda engine avval obyektning o'zidan qidiradi. Topmasa, uning [[Prototype]]iga (ya'ni Object.getPrototypeOf(obj)ga) o'tadi, u yerdan topmasa yuqoriga... — nullgacha. Bu prototype chain. Oxiri odatda Object.prototype null.
const hayvon = {
ovqatlan() { return `${this.ism} ovqatlanmoqda`; },
};
const it = Object.create(hayvon); // it'ning prototypesi — hayvon
it.ism = "Bobik";
console.log(it.ovqatlan()); // "Bobik ovqatlanmoqda" — merosdan
console.log(it.hasOwnProperty("ism")); // true — o'ziniki
console.log(it.hasOwnProperty("ovqatlan")); // false — merosTuzoq. Property o'qish zanjir bo'ylab boradi, lekin yozish har doim obyektning o'ziga yoziladi (prototypeni o'zgartirmaydi) — bu "property shadowing". Shuningdek, prototype'dagi umumiy obyekt/massivni barcha nusxalar baham ko'radi (mutatsiya xavfli).
Follow-up. "Object.create nima qiladi?" · "Prototype chainning oxiri nima?" (null) · "Property shadowing nima?"
S: __proto__ va prototype orasidagi farq nima? (Senior — chalkashtiruvchi)
J: Ta'rif. Ikkalasi ham prototypega tegishli, lekin butunlay boshqa narsalar.
prototype— faqat funksiyalarda (konstruktorlarda) bo'ladigan property.newbilan yaratilgan nusxalarning prototypesi shu bo'ladi.__proto__— har bir obyektda bo'ladigan, uning haqiqiy prototypesiga ([[Prototype]]ga) ishora qiluvchi geter/seter.
Mexanizm. new Foo() bajarilganda: yangiObyekt.__proto__ = Foo.prototype. Ya'ni nusxaning __proto__i konstruktorning prototypeiga bog'lanadi.
function Foo() {}
const f = new Foo();
console.log(f.__proto__ === Foo.prototype); // true
console.log(Foo.prototype.constructor === Foo); // true
console.log(f.prototype); // undefined (nusxada yo'q)
console.log(Object.getPrototypeOf(f) === Foo.prototype); // true — to'g'ri usul Tuzoq. __proto__ — eskirgan (deprecated), faqat brauzer moslikni saqlab qolgan. Production'da Object.getPrototypeOf(obj) va Object.setPrototypeOf(obj, proto) ishlating. Prototype'ni run-time'da o'zgartirish esa juda sekin (engine optimizatsiyasini buzadi).
Follow-up. "new ichida __proto__ qanday o'rnatiladi?" · "instanceof bu bilan qanday bog'liq?" · "Object.getPrototypeOf nega afzal?"
S: new operatori ichida nima sodir bo'ladi? Uni qo'lda yozib bering. (Senior)
J: Ta'rif. new konstruktor funksiyani chaqirib, yangi obyekt yaratadigan operator. U 4 qadamni bajaradi.
Mexanizm — new Foo(args) qadamlari:
- Yangi bo'sh obyekt yaratiladi:
{}. - Uning
[[Prototype]]iFoo.prototypega bog'lanadi. Fooshu yangi obyektthisbo'lgan holda chaqiriladi (argumentlar bilan).- Agar konstruktor obyekt qaytarmasa, avtomatik yangi obyekt qaytariladi (primitive qaytarsa — e'tiborsiz).
function myNew(Konstruktor, ...args) {
const obj = Object.create(Konstruktor.prototype); // 1 + 2
const natija = Konstruktor.apply(obj, args); // 3
return typeof natija === "object" && natija !== null ? natija : obj; // 4
}
function Foydalanuvchi(ism) { this.ism = ism; }
Foydalanuvchi.prototype.salom = function () { return `Salom, ${this.ism}`; };
const u = myNew(Foydalanuvchi, "Sardor");
console.log(u.salom()); // "Salom, Sardor" Tuzoq. Agar konstruktor explicit obyekt qaytarsa, new o'sha obyektni qaytaradi (yangi thisni emas). Primitive qaytarsa — e'tiborsiz qoldiriladi. newni unutsangiz, this global/undefined bo'lib, xato yuz beradi.
Follow-up. "Konstruktor return { } qilsa nima bo'ladi?" · "new.target nima?" · "Arrow'ni nega new bilan chaqirib bo'lmaydi?"
5-BO'LIM: Event loop, asinxronlik
S: Event loop nima? Chuqur tushuntiring. (Senior — eng muhim savol)
J: Ta'rif. JavaScript bir oqimli (single-threaded) — bir vaqtda bitta ish bajaradi. Event loop — asinxron operatsiyalarni (timer, tarmoq, promise) shu bir oqimda bloklamasdan boshqaradigan mexanizm.
Mexanizm — komponentlar:
- Call Stack — bajarilayotgan funksiyalar stegi (LIFO).
- Web/Node API —
setTimeout,fetch, DOM eventlari shu yerda (asosiy oqimdan tashqarida) kutadi. - Macrotask (Task) Queue —
setTimeout,setInterval, I/O, event callback'lari navbati. - Microtask Queue — Promise
.then/catch/finally,queueMicrotask,MutationObserver. Ustunroq.
Event loop qoidasi: Call stack bo'shashi bilan, event loop avval butun microtask queueni tozalaydi (hammasini), keyin bitta macrotask oladi, va yana microtasklarni tozalaydi. Ya'ni microtasklar har doim macrotasklardan oldin.
console.log("1"); // sinxron
setTimeout(() => console.log("2"), 0); // macrotask
Promise.resolve().then(() => console.log("3")); // microtask
console.log("4"); // sinxron
// Chiqish: 1, 4, 3, 2Tartib: sinxron (1, 4) microtasklar (3) macrotasklar (2).
Tuzoq. setTimeout(fn, 0) "darrov" bajarilmaydi — u macrotask navbatiga tushadi va barcha microtasklardan keyin ishlaydi. Ko'p microtask navbatga qo'yilsa, macrosk uzoq "och" qolishi (starvation) mumkin.
Follow-up. "Microtask va macrotask farqi?" · "process.nextTick (Node) qayerga tushadi?" (microtasklardan ham oldin) · "Nega JS single-thread bo'la turib asinxron?"
S: Quyidagi kod qanday tartibda chiqadi? (Senior — event loop tuzog'i)
console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => {
console.log("C");
setTimeout(() => console.log("D"), 0);
});
Promise.resolve().then(() => console.log("E"));
console.log("F");J: Javob: A F C E B D.
Qadam-baqadam:
- Sinxron kod:
A, keyinFchiqadi.setTimeout(B)— macrotask navbatiga. Ikkala.then— microtask navbatiga. - Stack bo'shadi microtasklar tozalanadi:
Cchiqadi (vasetTimeout(D)macrotask navbatiga qo'shiladi), keyinEchiqadi. - Microtasklar tugadi bitta macrotask olinadi:
B. - Yana macrotask:
D.
Yakuniy: A F C E B D.
Tuzoq. C ichidagi setTimeout(D) kechroq navbatga tushgani uchun, B (avvalroq qo'yilgan) undan oldin chiqadi. Va microtasklar (C, E) har doim B/Ddan oldin. Tartibni chalkashtirish oson.
Follow-up. "Agar D setTimeout emas, Promise.then bo'lsa-chi?" · "B va D orasida yana microtask bo'lsa?" · "Bu tartib brauzer va Node'da bir xilmi?"
S: Promise nima? Uning holatlari qanday? (Middle)
J: Ta'rif. Promise — asinxron operatsiyaning kelajakdagi natijasini ifodalovchi obyekt. Callback hell o'rniga zanjir (chaining) yozishga imkon beradi.
Mexanizm — 3 holat:
- pending — boshlang'ich, hali natija yo'q.
- fulfilled — muvaffaqiyatli bajarildi (
resolvechaqirilgan). - rejected — xato bilan tugadi (
rejectchaqirilgan).
Holat faqat bir marta pending'dan fulfilled yoki rejected'ga o'tadi — keyin o'zgarmaydi (settled/immutable). .then fulfilled'ni, .catch rejected'ni ushlaydi. Har .then yangi promise qaytaradi — shuning uchun zanjir hosil bo'ladi.
function malumotOl() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const ok = true;
ok ? resolve({ id: 1 }) : reject(new Error("Xato"));
}, 500);
});
}
malumotOl()
.then((data) => data.id) // yangi promise qaytaradi
.then((id) => console.log(id)) // 1
.catch((err) => console.error(err.message))
.finally(() => console.log("Tugadi")); // har holatda ishlaydi Tuzoq. .then ichida qaytarilgan qiymat keyingi .thenga uzatiladi. Agar promise qaytarsangiz, u "unwrap" qilinadi (kutiladi). .catchdan keyin zanjir davom etadi (resolved holatda), agar .catch qayta throw qilmasa.
Follow-up. "Promise holati qayta o'zgaradimi?" (yo'q) · ".then nima qaytaradi?" (yangi promise) · "Unhandled rejection nima?"
S: Promise.all, race, allSettled, any farqi nima? (Middle)
J: Ta'rif. To'rttasi ham promise'lar massivini boshqaradi, lekin qachon "tugash" va nima qaytarish bilan farqlanadi.
| Metod | Qachon resolve | Qachon reject |
|---|---|---|
all |
Hammasi fulfilled bo'lsa | Bittasi reject bo'lsa (fail-fast) |
race |
Birinchi settled (fulfilled yoki rejected) | Birinchi rejected bo'lsa |
allSettled |
Hammasi settled bo'lsa (hech qachon reject qilmaydi) | — |
any |
Birinchi fulfilled bo'lsa | Hammasi reject bo'lsa (AggregateError) |
const p1 = Promise.resolve(1);
const p2 = Promise.reject("xato");
const p3 = Promise.resolve(3);
await Promise.all([p1, p3]); // [1, 3]
// await Promise.all([p1, p2]); // throw "xato" (bittasi yiqildi)
await Promise.allSettled([p1, p2]); // [{status:"fulfilled",value:1},{status:"rejected",reason:"xato"}]
await Promise.any([p2, p3]); // 3 (birinchi muvaffaqiyatli)
await Promise.race([p1, p2]); // 1 (birinchi settled) Tuzoq. Promise.all fail-fast — bitta promise reject bo'lsa, qolganlar bekor qilinmasa ham, natija darrov reject. Agar "hammasini kutib, xatolarni ham ko'rmoqchi" bo'lsangiz — allSettled ishlating.
Follow-up. "1000 ta so'rov bor, bittasi yiqilsa hammasi to'xtamasin — qaysi metod?" (allSettled) · "race bilan timeout qanday yasaysiz?" · "all rad etilganda qolgan promise'lar to'xtaydimi?" (yo'q, faqat natija e'tiborsiz).
S: async/await nima? Xatoni qanday boshqarasiz? (Middle)
J: Ta'rif. async/await — Promise ustidagi sintaktik shakar; asinxron kodni sinxrondek o'qishga imkon beradi. async funksiya har doim Promise qaytaradi, await esa promise settle bo'lguncha kutadi.
Mexanizm. await funksiyani to'xtatib (suspend), boshqaruvni event loop'ga qaytaradi; promise resolve bo'lgach, funksiya qolgan joyidan davom etadi (aslida bu — microtask'da davom etish). Xatoni try/catch bilan ushlaysiz — sinxrondek.
async function foydalanuvchiOl(id) {
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
return data;
} catch (err) {
console.error("Xato:", err.message);
throw err; // yuqoriga uzatish
} finally {
console.log("So'rov tugadi");
}
} Tuzoq. Ketma-ket await (biri-biridan mustaqil bo'lsa ham) sekin — har biri navbat bilan kutadi. Parallel kerak bo'lsa Promise.all ishlating:
// Sekin — ketma-ket (500ms + 500ms)
const a = await olA();
const b = await olB();
// Tez — parallel (500ms)
const [a, b] = await Promise.all([olA(), olB()]); Follow-up. "async funksiya nima qaytaradi?" (Promise) · "Loop ichida await xavfimi?" (ketma-ket bo'ladi — for...of bilan atayin, aks holda Promise.all) · "await ni try/catchsiz ishlatsangiz nima bo'ladi?"
S: Callback hell nima va uni qanday hal qilasiz? (Junior)
J: Ta'rif. Callback hell (yoki "pyramid of doom") — ichma-ich joylashgan callback'lar tufayli kodning o'ngga qarab chuqurlashib, o'qib/xatosini boshqarib bo'lmas holga kelishi.
// Callback hell
malumotOl(id, (user) => {
buyurtmalarOl(user, (orders) => {
tafsilotOl(orders[0], (detail) => {
console.log(detail); // 3 qavat chuqurlik
});
});
});
// Promise zanjir
malumotOl(id)
.then((user) => buyurtmalarOl(user))
.then((orders) => tafsilotOl(orders[0]))
.then((detail) => console.log(detail));
// async/await — eng toza
async function ishla(id) {
const user = await malumotOl(id);
const orders = await buyurtmalarOl(user);
const detail = await tafsilotOl(orders[0]);
console.log(detail);
}Mexanizm — nega yomon: har callback o'z scope'ini yaratadi, xato boshqarish har darajada takrorlanadi, tartibni o'zgartirish qiyin, return qiymat uzatolmaydi.
Tuzoq. Promise zanjirida .catchni unutmang — aks holda unhandled rejection. async/await'da try/catch bilan qoplang.
Follow-up. "Promise callback hell'ni to'liq yo'qotadimi?" · "async/await'ning ichida nima?" (Promise) · "Xato boshqarishni qanday markazlashtirasiz?"
6-BO'LIM: Coercion, taqqoslash, tuzoqlar
S: == va === orasidagi farq nima? (Middle)
J: Ta'rif. === — qat'iy tenglik (strict): tur va qiymatni tekshiradi, konvertatsiya qilmaydi. == — erkin tenglik (loose): turlar farq qilsa, avval type coercion qiladi, keyin taqqoslaydi.
Mexanizm. == da JS qoidalar bo'yicha bir turni ikkinchisiga aylantiradi (odatda songa). Bu ko'p kutilmagan natijalarga olib keladi.
console.log(1 == "1"); // true — "1" 1
console.log(0 == false); // true — false 0
console.log(null == undefined); // true — maxsus qoida
console.log(null == 0); // false — null faqat undefined'ga teng
console.log("" == 0); // true — "" 0
console.log([] == false); // true — [] "" 0
console.log(NaN == NaN); // false — NaN hech narsaga (o'ziga ham) teng emas
console.log(1 === "1"); // false — tur farqli Tuzoq. null == undefined true, lekin null == 0 false. Va NaN === NaN false. Shuning uchun doim === ishlating (null == undefined tekshiruvidan tashqari, u maxsus foydali).
Follow-up. "== coercion qoidalarini ayting" · "null nima bilan == bo'ladi?" (faqat undefined va null) · "[] == ![] nima beradi?" (true — mashhur tuzoq).
S: Truthy va falsy qiymatlar nima? Falsy'larni sanang. (Middle)
J: Ta'rif. Boolean kontekstida (if, &&, ||) har qiymat true yoki falsega aylanadi. Falsy — falsega aylanadigan qiymatlar; qolgan hammasi truthy.
Falsy qiymatlar (aynan 8 ta / 7 ta noyob):
false
0 // va -0
0n // BigInt nol
"" // bo'sh string
null
undefined
NaN
// document.all — brauzerdagi tarixiy istisnoQolgan hamma narsa truthy, jumladan hiyla qiluvchilar:
if ("0") { } // truthy — bo'sh bo'lmagan string
if ([]) { } // truthy — bo'sh massiv ham!
if ({}) { } // truthy — bo'sh obyekt ham!
if ("false") { } // truthy — string "false" Tuzoq. Bo'sh massiv [] va bo'sh obyekt {} — truthy! Massiv bo'shligini if(arr) bilan emas, if(arr.length === 0) bilan tekshiring. Va if ("0") truthy — string bo'sh emas.
Follow-up. "[] truthy'mi?" (ha) · "if(arr.length) nima uchun ishlaydi?" · "Boolean([]) nima qaytaradi?" (true).
S: 0.1 + 0.2 === 0.3 nega false? (Senior — klassik)
J: Javob: false, chunki 0.1 + 0.2 === 0.30000000000000004.
Mexanizm. JS sonlar IEEE 754 double-precision (64-bit floating point) formatida saqlanadi. 0.1 va 0.2 ikkilik (binary) sistemada aniq ifodalanmaydi — xuddi 1/3 o'nlikda 0.333... bo'lgani kabi. Ular yaqin qiymatga yaxlitlanadi, va qo'shilganda kichik xato to'planadi.
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // false
// To'g'ri taqqoslash — epsilon bilan
const teng = Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON;
console.log(teng); // true
// Pul bilan ishlaganda — butun songa (tiyin/sent)
const narx = 10; // 0.10 so'm o'rniga 10 tiyinTuzoq. Bu barcha tillarga xos (JS'ga emas — float standarti). Moliyaviy hisob-kitobda hech qachon float ishlatmang — butun sonlar (eng kichik birlik) yoki maxsus decimal kutubxona ishlating.
Follow-up. "Buni qanday to'g'ri taqqoslaysiz?" (Number.EPSILON) · "Pul bilan qanday ishlaysiz?" · "Number.MAX_SAFE_INTEGER nima?"
S: typeof null nima qaytaradi va nega? (Middle — klassik tuzoq)
J: Javob: "object" — bu JavaScript'ning tarixiy XATOSI (bug).
Mexanizm. JS'ning dastlabki versiyasida qiymatlar teg (tag) bitlar bilan saqlangan: obyektlar 000 teg bilan boshlanardi, va null — bo'sh (null) ko'rsatkich, ya'ni 0x00, ham 000 teg bilan chiqib qolgan. Shuning uchun typeof null "object" deb topadi. Bu buni tuzatish eski kodni buzgani uchun standart shundayligicha qoldirilgan.
console.log(typeof null); // "object" (bug)
console.log(typeof undefined); // "undefined"
console.log(typeof function(){}); // "function"
console.log(typeof []); // "object" (massiv ham obyekt)
console.log(typeof NaN); // "number" (!)
// null'ni to'g'ri tekshirish
const x = null;
console.log(x === null); // true — aniq usul Tuzoq. nullni aniqlash uchun typeof ishlatmang — x === null ishlating. Massivni aniqlashda ham typeof "object" beradi — Array.isArray() ishlating.
Follow-up. "Massivni qanday aniqlaysiz?" (Array.isArray) · "typeof NaN nima?" ("number") · "null va undefined farqi?"
S: [1, 2, 3].map(parseInt) nima qaytaradi? (Senior — mashhur tuzoq)
J: Javob: [1, NaN, NaN].
Mexanizm. map callback'ga uch argument uzatadi: (element, index, array). parseInt esa ikki argument oladi: parseInt(string, radix) (radix — sanoq sistemasi asosi). Demak:
parseInt("1", 0)radix 0 e'tiborsiz1parseInt("2", 1)radix 1 yaroqsizNaNparseInt("3", 2)radix 2 (ikkilik), lekin "3" ikkilikda yo'qNaN
console.log([1, 2, 3].map(parseInt)); // [1, NaN, NaN]
// To'g'ri yechim — argumentni cheklang
console.log([1, 2, 3].map((x) => parseInt(x, 10))); // [1, 2, 3]
console.log([1, 2, 3].map(Number)); // [1, 2, 3]
console.log(["1", "2", "3"].map(Number)); // [1, 2, 3] Tuzoq. mapga ko'p argumentli funksiyani to'g'ridan-to'g'ri uzatmang. parseInt, parseFloat kabilarni har doim wrap qiling yoki Number ishlating.
Follow-up. "parseIntning ikkinchi argumenti nima?" (radix) · "map(Number) nega ishlaydi?" (Number bitta argument oladi) · "["10","10","10"].map(parseInt) nima beradi?" ([10, NaN, 2]).
S: Primitive va reference turlari orasidagi farq nima? (Middle)
J: Ta'rif. JS'da qiymatlar ikki toifa: primitive (string, number, boolean, null, undefined, symbol, bigint) va reference (object, array, function).
Mexanizm.
- Primitive — qiymat stackda to'g'ridan-to'g'ri saqlanadi. Nusxalanganda qiymat ko'chiriladi (mustaqil).
- Reference — qiymat heapda, o'zgaruvchida esa unga havola (reference) turadi. Nusxalanganda havola ko'chiriladi (ikkalasi bir obyektni ko'rsatadi).
// Primitive — mustaqil nusxa
let a = 10;
let b = a;
b = 20;
console.log(a); // 10 — o'zgarmadi
// Reference — umumiy havola
let obj1 = { son: 10 };
let obj2 = obj1;
obj2.son = 20;
console.log(obj1.son); // 20 — ikkalasi bir obyekt!
// Taqqoslash ham reference bo'yicha
console.log({} === {}); // false — har xil havola
console.log([1] === [1]); // false Tuzoq. Obyektni funksiyaga uzatsangiz, funksiya ichida uni mutatsiya qilsa, tashqaridagi ham o'zgaradi (havola bir). Va ikki obyekt "bir xil ko'rinsa" ham === false beradi — chunki havolalar farqli.
Follow-up. "Funksiyaga obyekt uzatilsa, u pass-by-value'mi yoki reference?" (havola qiymat sifatida uzatiladi) · "Ikki obyektni ichi bo'yicha qanday taqqoslaysiz?" · "String primitive'mi?"
S: Shallow copy va deep copy farqi nima? Qanday qilasiz? (Middle)
J: Ta'rif. Shallow copy — obyektning faqat birinchi darajasini nusxalaydi; ichki (nested) obyektlar hali umumiy havola. Deep copy — barcha darajalarni to'liq, mustaqil nusxalaydi.
Mexanizm. Spread (...) va Object.assign — shallow. Ichki obyekt hali baham ko'riladi. Deep uchun rekursiv nusxalash yoki structuredClone kerak.
const asl = { ism: "Ali", manzil: { shahar: "Toshkent" } };
// Shallow — ichki obyekt umumiy
const shallow = { ...asl };
shallow.manzil.shahar = "Samarqand";
console.log(asl.manzil.shahar); // "Samarqand" — asl ham o'zgardi!
// Deep — to'liq mustaqil
const deep = structuredClone(asl); // zamonaviy, tavsiya etiladi
deep.manzil.shahar = "Buxoro";
console.log(asl.manzil.shahar); // o'zgarmaydi
// Eski usul (cheklovlar bilan)
const deep2 = JSON.parse(JSON.stringify(asl)); // function, Date, undefined yo'qoladi Tuzoq. JSON.parse(JSON.stringify(obj)) — deep copy'ning ommaviy, lekin nuqsonli usuli: funksiyalar, undefined, Symbol yo'qoladi; Date string'ga aylanadi; sirkulyar havola xato beradi. Zamonaviy structuredClone() afzal.
Follow-up. "structuredClone nimalarni ko'chira olmaydi?" (funksiya, DOM) · "Spread deep copy qiladimi?" (yo'q) · "Sirkulyar havolani qanday nusxalaysiz?"
7-BO'LIM: Funksiyalar — HOF, currying, debounce/throttle
S: Higher-order function (HOF) nima? (Middle)
J: Ta'rif. HOF — funksiyani argument sifatida qabul qiladigan yoki funksiya qaytaradigan funksiya. JS'da funksiyalar "birinchi darajali fuqaro" (first-class citizens) bo'lgani uchun bu mumkin.
Mexanizm. Funksiyalar qiymat kabi — o'zgaruvchiga biriktirsa, uzatsa, qaytarsa bo'ladi. Bu abstraktsiya va qayta ishlatishga imkon beradi.
// Argument sifatida funksiya oladi
[1, 2, 3].map((x) => x * 2); // map — HOF
// Funksiya qaytaradi
function kupaytiruvchi(n) {
return (x) => x * n; // yangi funksiya qaytaradi
}
const ikkiBaravar = kupaytiruvchi(2);
console.log(ikkiBaravar(5)); // 10
// Klassik HOF'lar: map, filter, reduce, forEach, sort, setTimeout Tuzoq. HOF'ga funksiyani chaqirib emas, havola sifatida uzating: arr.map(fn) (to'g'ri), arr.map(fn()) (xato — natijasini uzatadi).
Follow-up. "map, filter, reduce — HOF'mi?" (ha) · "First-class function nima?" · "Callback va HOF farqi?"
S: map, filter, reduce farqi nima? reduce bilan qolganini yozing. (Middle)
J: Ta'rif.
map— har elementni transformatsiya qilib, bir xil uzunlikdagi yangi massiv qaytaradi.filter— shartga mos elementlarni saqlab, qisqaroq massiv qaytaradi.reduce— massivni bitta qiymatga (son, obyekt, massiv — nimaga xohlasangiz) yig'adi.
Mexanizm. Uchalasi ham immutable — asl massivni o'zgartirmaydi, yangi qiymat qaytaradi. reduce eng umumiy — map va filterni undan yasash mumkin.
const sonlar = [1, 2, 3, 4, 5];
sonlar.map((x) => x * 2); // [2, 4, 6, 8, 10]
sonlar.filter((x) => x % 2); // [1, 3, 5] (toq)
sonlar.reduce((yigindi, x) => yigindi + x, 0); // 15
// map va filter'ni reduce bilan yasash
const map2 = sonlar.reduce((acc, x) => [...acc, x * 2], []);
const filter2 = sonlar.reduce((acc, x) => (x % 2 ? [...acc, x] : acc), []); Tuzoq. reduce da boshlang'ich qiymatni (, 0 yoki , []) unutmang — aks holda bo'sh massivda xato beradi, va birinchi element accumulator bo'lib qolib, natija noto'g'ri chiqishi mumkin.
Follow-up. "reducening boshlang'ich qiymati bo'lmasa nima bo'ladi?" · "forEach va map farqi?" (forEach qiymat qaytarmaydi) · "Qay biri immutable?"
S: Currying nima? Misol bilan yozing. (Senior)
J: Ta'rif. Currying — bir nechta argumentli funksiyani, har biri bitta argument oladigan ketma-ket funksiyalar zanjiriga aylantirish. f(a, b, c) f(a)(b)(c).
Mexanizm. Har chaqiruv keyingi argumentni closure orqali "eslab", yangi funksiya qaytaradi; barcha argumentlar yig'ilgach, natija hisoblanadi. Bu partial application (qisman qo'llash) va qayta ishlatishga imkon beradi.
// Oddiy
const qoshish = (a) => (b) => (c) => a + b + c;
console.log(qoshish(1)(2)(3)); // 6
// Universal curry
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) return fn.apply(this, args);
return (...next) => curried.apply(this, [...args, ...next]);
};
}
const kop = curry((a, b, c) => a * b * c);
console.log(kop(2)(3)(4)); // 24
console.log(kop(2, 3)(4)); // 24 — moslashuvchan
console.log(kop(2)(3, 4)); // 24
// Amaliy — partial application
const salomBer = (salom) => (ism) => `${salom}, ${ism}!`;
const assalom = salomBer("Assalomu alaykum");
console.log(assalom("Ali")); // "Assalomu alaykum, Ali!" Tuzoq. fn.length default parametr yoki rest (...args) bo'lsa noto'g'ri sanaydi (ular hisobga olinmaydi) — universal curry buzilishi mumkin.
Follow-up. "Currying va partial application farqi?" · "fn.length nima qaytaradi?" · "Currying qanday real foyda beradi?"
S: Debounce va throttle farqi nima? Ikkalasini yozing. (Senior — juda ko'p so'raladi)
J: Ta'rif. Ikkalasi ham funksiya chaqirilishini cheklaydi (rate limiting), lekin boshqacha:
- Debounce — funksiya so'nggi chaqiruvdan keyin belgilangan pauza o'tsagina ishlaydi. "Foydalanuvchi to'xtaganda ishla." (qidiruv inputi).
- Throttle — funksiya har belgilangan intervalda ko'pi bilan bir marta ishlaydi. "Muntazam, lekin siyrak ishla." (scroll, resize).
Mexanizm. Debounce har chaqiruvda oldingi timer'ni bekor qiladi va yangisini qo'yadi. Throttle esa oxirgi ishlagan vaqtni eslab, interval o'tmaguncha yangi chaqiruvni e'tiborsiz qoldiradi.
// Debounce — foydalanuvchi to'xtaganidan T ms keyin
function debounce(fn, kutish) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), kutish);
};
}
// Throttle — har T ms da ko'pi bilan bir marta
function throttle(fn, oraliq) {
let oxirgi = 0;
return function (...args) {
const hozir = Date.now();
if (hozir - oxirgi >= oraliq) {
oxirgi = hozir;
fn.apply(this, args);
}
};
}
// Ishlatish
const qidir = debounce((q) => console.log("Qidiruv:", q), 300);
const scrollHandler = throttle(() => console.log("Scroll"), 200);Tuzoq. Ikkalasini almashtirib yuborish — keng tarqalgan xato. Qidiruv inputiga throttle qo'ysangiz, har 200ms da so'rov ketaveradi (kerak emas); scroll'ga debounce qo'ysangiz, foydalanuvchi to'xtamaguncha umuman ishlamaydi.
Follow-up. "Qidiruv inputiga qay biri?" (debounce) · "Scroll/resize'ga qay biri?" (throttle) · "Leading va trailing edge nima?" · "thisni nega apply bilan uzatasiz?"
8-BO'LIM: Zamonaviy sintaksis (ES6+)
S: Destructuring nima? Misollar bilan. (Junior)
J: Ta'rif. Destructuring — massiv yoki obyektdan qiymatlarni alohida o'zgaruvchilarga qulay ajratib olish sintaksisi.
// Obyekt destructuring
const user = { ism: "Laylo", yosh: 25, shahar: "Toshkent" };
const { ism, yosh } = user;
const { shahar: joy } = user; // qayta nomlash: joy = "Toshkent"
const { mamlakat = "UZ" } = user; // default qiymat
// Massiv destructuring
const [birinchi, ikkinchi, ...qolgan] = [1, 2, 3, 4, 5];
console.log(birinchi, ikkinchi, qolgan); // 1 2 [3, 4, 5]
// Almashtirish (swap) — vaqtinchalik o'zgaruvchisiz
let a = 1, b = 2;
[a, b] = [b, a]; // a=2, b=1
// Funksiya parametrida
function chiz({ x = 0, y = 0 } = {}) {
return `${x},${y}`;
}
chiz({ x: 10 }); // "10,0"
// Nested
const data = { user: { profil: { avatar: "img.png" } } };
const { user: { profil: { avatar } } } = data; Tuzoq. {}ni statement boshida yozsangiz JS uni blok deb o'ylaydi — qavsga oling: ({ a } = obj). Va nested destructuring'da tashqi kalit o'zgaruvchi yaratmaydi (faqat ichkariga yo'l).
Follow-up. "Default qiymat qanday beriladi?" · "Swap'ni qanday qilasiz?" · "= {} fallback nega kerak?"
S: Spread va rest operatorlari farqi nima (...)? (Middle)
J: Ta'rif. Ikkalasi ham ... sintaksisi, lekin teskari ish qiladi:
- Spread — massiv/obyektni yoyadi (elementlarga ajratadi). "Ochish."
- Rest — bir nechta elementni bitta massiv/obyektga yig'adi. "Yig'ish."
Mexanizm. Kontekst hal qiladi: chaqiruv/literal ichida — spread; funksiya parametri yoki destructuring chap tomonida — rest.
// Spread — yoyish
const a = [1, 2, 3];
const b = [...a, 4, 5]; // [1,2,3,4,5]
const obj = { ...{ x: 1 }, y: 2 }; // { x:1, y:2 }
Math.max(...a); // 3 — argumentlarga yoyadi
const nusxa = [...a]; // shallow copy
// Rest — yig'ish
function yigindi(...sonlar) { // barcha argumentlarni massivga
return sonlar.reduce((s, x) => s + x, 0);
}
yigindi(1, 2, 3, 4); // 10
const [bosh, ...tana] = [1, 2, 3]; // bosh=1, tana=[2,3]
const { id, ...qolgani } = { id: 1, a: 2, b: 3 }; // qolgani={a:2,b:3} Tuzoq. Rest parametr oxirgi bo'lishi shart: function f(...a, b) — SyntaxError. Va spread bilan obyekt merge qilganda oxirgi kalit yutadi (tartib muhim).
Follow-up. "Rest oxirgimi yoki istalgan joyda?" (oxirgi) · "Spread deep copy qiladimi?" (yo'q, shallow) · "arguments va rest farqi?"
S: Optional chaining (?.) va nullish coalescing (??) nima? (Middle)
J: Ta'rif.
?.— obyekt zanjiridanull/undefinedbo'lsa, xato tashlamasdanundefinedqaytaradi.??— chap tomonnullyokiundefinedbo'lsagina o'ng tomonni beradi (||dan farqli — u barcha falsy'da beradi).
Mexanizm. ?. — agar chap tomon nullish bo'lsa, keyingi murojaatni "qisqa tutashtiradi" (short-circuit). ?? — faqat nullish'ni tekshiradi, 0 va "" kabi to'g'ri falsy qiymatlarni saqlaydi.
const user = { profil: { manzil: null } };
console.log(user.profil?.manzil?.shahar); // undefined (xato yo'q)
console.log(user.sozlama?.tema); // undefined
console.log(user.metod?.()); // xavfsiz metod chaqiruvi
console.log(user.arr?.[0]); // xavfsiz indeks
// ?? vs ||
const son = 0;
console.log(son || 10); // 10 — 0 falsy, o'chib ketdi
console.log(son ?? 10); // 0 — 0 saqlanadi
console.log(null ?? "default"); // "default" Tuzoq. count || 10 — agar count 0 bo'lsa, 10 beradi (xato!). Default qiymat kerak bo'lsa, count ?? 10 ishlating — u faqat null/undefinedni almashtiradi. "" (bo'sh string) bilan ham shu muammo.
Follow-up. "?? va || qachon farqli natija beradi?" (0, "", falseda) · "?.() nima qiladi?" · "a ?? b || c yozsa bo'ladimi?" (yo'q — qavs kerak, SyntaxError).
S: Tagged template literal nima? (Middle)
J: Ta'rif. Tagged template — template literalni funksiya bilan qayta ishlash imkoni. Funksiya (tag) string qismlari va o'zgaruvchi qiymatlarini alohida oladi.
Mexanizm. tag\...`yozilganda,tag funksiya ikki qism bilan chaqiriladi: (1) string bo'laklari massivi, (2) ichiga qo'yilgan qiymatlar (...values`). Bu — string'ni maxsus formatlash, escaping, i18n uchun.
function ajratib(strings, ...values) {
return strings.reduce(
(natija, str, i) => `${natija}${str}<b>${values[i] ?? ""}</b>`,
""
);
}
const ism = "Ali", yosh = 25;
console.log(ajratib`Ism: ${ism}, yosh: ${yosh}`);
// "Ism: <b>Ali</b>, yosh: <b>25</b>"
// Amaliy misol — styled-components shu tamoyilda ishlaydi:
// const Button = styled.button`color: red;` Tuzoq. strings massivi har doim valuesdan bitta ko'p elementga ega (chetlaridagi bo'sh string'lar ham kiradi). Buni hisobga olmasangiz, indekslar chalkashadi.
Follow-up. "strings.length va values.length munosabati?" · "Styled-components buni qanday ishlatadi?" · "String.raw nima?"
9-BO'LIM: Ma'lumot tuzilmalari va boshqa mavzular
S: Map va oddiy obyekt ({}) orasidagi farq nima? (Middle)
J: Ta'rif. Ikkalasi ham kalit-qiymat saqlaydi, lekin Map — maxsus, kuchliroq tuzilma.
Farqlar:
| Xususiyat | Obyekt {} |
Map |
|---|---|---|
| Kalit turi | faqat string/symbol | istalgan tur (obyekt, funksiya ham) |
| Tartib | to'liq kafolatlanmagan | kiritish tartibi saqlanadi |
| O'lcham | Object.keys().length |
.size |
| Iteratsiya | for...in / Object.entries |
to'g'ridan-to'g'ri iterable |
| Ishlash | tez-tez o'zgarishga sekinroq | katta/dinamik uchun tezroq |
| Prototype | meros kalitlar xavfi bor | toza (prototype yo'q) |
const map = new Map();
const obyektKalit = { id: 1 };
map.set(obyektKalit, "qiymat"); // obyekt — kalit!
map.set("ism", "Ali");
console.log(map.get(obyektKalit)); // "qiymat"
console.log(map.size); // 2
for (const [k, v] of map) { /* ... */ } // oson iteratsiya Tuzoq. Oddiy obyektda kalitlar string'ga aylanadi: obj[1] va obj["1"] — bir xil. Va obj.toString kabi meros kalitlar bilan to'qnashuv bo'lishi mumkin. Dinamik, tez o'zgaruvchi kalit-qiymat uchun Map afzal.
Follow-up. "Obyektda obyektni kalit qilib bo'ladimi?" (yo'q, string'ga aylanadi) · "Map qachon afzal?" · "Object.create(null) nima uchun?"
S: WeakMap/WeakSet nima? Nima uchun kerak? (Middle)
J: Ta'rif. WeakMap/WeakSet — kalitlari faqat obyekt bo'ladigan, va kalitlarni "kuchsiz" (weak) ushlaydigan kolleksiya. Agar obyektga boshqa havola qolmasa, garbage collector uni (va yozuvni) tozalaydi.
Mexanizm. Oddiy Map kalit-obyektni ushlab turadi (strong reference) — GC uni o'chira olmaydi, xotira sizadi. WeakMap esa kalitni ushlamaydi; obyekt yo'qolsa, yozuv ham avtomatik yo'qoladi. Shuning uchun WeakMap iteratsiya qilinmaydi va .sizei yo'q (mazmuni istalgan payt o'zgarishi mumkin).
const keshi = new WeakMap();
let user = { id: 1 };
keshi.set(user, "hisoblangan malumot");
console.log(keshi.get(user)); // "hisoblangan malumot"
user = null; // endi obyektga havola yo'q
// GC user'ni va WeakMap yozuvini avtomatik tozalaydi — memory leak yo'qAmaliy foyda: DOM elementlariga bog'liq metama'lumot saqlash, private data, memoization keshi — obyekt yo'qolsa avtomatik tozalanadi.
Tuzoq. WeakMapni iteratsiya qilib bo'lmaydi (for...of yo'q), .size yo'q, primitive kalit qo'ya olmaysiz. Umumiy maqsad uchun Map, xotira-sezgir kesh uchun WeakMap.
Follow-up. "Nega WeakMap iteratsiya qilinmaydi?" · "Memory leak'ni qanday oldini oladi?" · "DOM metama'lumotini qayerda saqlaysiz?"
S: Symbol nima? Qayerda ishlatiladi? (Middle)
J: Ta'rif. Symbol — ES6'dagi yangi primitive tur; har bir Symbol noyob va o'zgarmas (immutable), hatto bir xil tavsif bilan yaratsangiz ham.
Mexanizm. Symbol("x") !== Symbol("x") — har chaqiruv yangi, takrorlanmas qiymat beradi. Obyektda to'qnashmaydigan (collision-free) kalit sifatida ishlatiladi; for...in va Object.keysda ko'rinmaydi (yashirin).
const id = Symbol("id");
const user = { [id]: 123, ism: "Ali" };
console.log(user[id]); // 123
console.log(Object.keys(user)); // ["ism"] — Symbol yashirin
// Well-known symbols — engine xatti-harakatini sozlash
const obj = {
[Symbol.iterator]() { // obyektni iterable qiladi
let i = 0;
return { next: () => (i < 3 ? { value: i++, done: false } : { value: undefined, done: true }) };
},
};
console.log([...obj]); // [0, 1, 2]
// Global registry
const s = Symbol.for("app.id"); // umumiy registrdan
console.log(Symbol.for("app.id") === s); // true Tuzoq. Symbol yashirin, lekin maxfiy emas — Object.getOwnPropertySymbols() bilan topiladi. Va Symbol("x") === Symbol("x") false (har biri noyob); umumiy kerak bo'lsa Symbol.for().
Follow-up. "Symbol.iterator nima?" · "Symbol.for va oddiy Symbol farqi?" · "Symbol'ni JSON.stringify qanday ko'radi?" (e'tiborsiz qoldiradi).
S: Generator va iterator nima? (Senior)
J: Ta'rif.
- Iterator —
next()metodi bilan{ value, done }qaytaradigan, ketma-ket qiymat beradigan obyekt. - Generator —
function*bilan yoziladigan,yieldorqali to'xtab-davom etadigan funksiya; avtomatik iterator qaytaradi.
Mexanizm. Generator funksiya chaqirilganda darrov ishlamaydi — iterator obyekt qaytaradi. Har .next()da yieldgacha ishlaydi, qiymat qaytaradi va to'xtaydi (holatini eslab). Bu — lazy evaluation, cheksiz ketma-ketliklar, va async oqimlar uchun asos.
function* sonlarGeneratori() {
yield 1;
yield 2;
yield 3;
}
const it = sonlarGeneratori();
console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log([...sonlarGeneratori()]); // [1, 2, 3]
// Cheksiz ketma-ketlik — lazy
function* cheksiz() {
let i = 0;
while (true) yield i++;
}
const gen = cheksiz();
console.log(gen.next().value, gen.next().value); // 0 1 — faqat kerakligini hisoblaydi Tuzoq. Generator holatga ega — bir marta oxirigacha borgan iterator qayta ishlamaydi (done: true qoladi). Har safar yangi iterator kerak. [...gen] iteratorni "sarflaydi".
Follow-up. "yield va return farqi generatorda?" · "yield* (delegatsiya) nima?" · "Redux-saga generator'ni nega ishlatadi?"
S: Garbage collection JS'da qanday ishlaydi? Memory leak sabablari? (Senior)
J: Ta'rif. JS xotirani avtomatik boshqaradi — garbage collector (GC) endi kerak bo'lmagan obyektlarni topib, xotirani bo'shatadi. Asosiy algoritm — Mark-and-Sweep.
Mexanizm. GC "root"lardan (global obyekt, joriy call stack, closure'lar) boshlab, erishish mumkin (reachable) bo'lgan barcha obyektlarni belgilaydi (mark). Belgilanmagan (hech qayerdan havola yo'q) obyektlar o'chiriladi (sweep). Ya'ni mezon — "erishuvchanlik" (reachability), reference count emas (shuning uchun sirkulyar havola muammo emas).
Memory leak — asosiy sabablar:
// 1. Global o'zgaruvchilar — hech qachon tozalanmaydi
function leak() { keraksiz = new Array(1000000); } // var/let'siz — global!
// 2. Unutilgan timer/interval
setInterval(() => { /* katta obyektni ushlaydi */ }, 1000); // clearInterval yo'q
// 3. Olib tashlanmagan event listener
element.addEventListener("click", handler); // removeEventListener yo'q
// 4. Closure'da katta obyektni keraksiz ushlash
// 5. DOM'dan o'chirilgan, lekin JS'da havola qolgan elementlar (detached DOM) Tuzoq. GC'ni qo'lda chaqirib bo'lmaydi (ishonchli tarzda). Va GC bor deb xotirani e'tiborsiz qoldirmang — SPA'larda unutilgan listener/timer/closure sekin-asta xotirani "yeydi". WeakMap/WeakRef bu holatlarda yordam beradi.
Follow-up. "Mark-and-sweep nima?" · "Sirkulyar havola leak beradimi?" (zamonaviy GC'da yo'q) · "SPA'da leak'ni qanday topasiz?" (DevTools Memory profiler).
S: ESM (ES Modules) va CommonJS farqi nima? (Middle)
J: Ta'rif. Ikkalasi ham JS modul sistemasi, lekin sintaksis va yuklash mexanizmi bilan farqlanadi.
- CommonJS (
require/module.exports) — Node.js'ning klassik tizimi, sinxron, run-time'da yuklanadi. - ESM (
import/export) — standart, brauzer va zamonaviy Node, asinxron, statik (compile-time) tahlil qilinadi.
Mexanizm.
| Xususiyat | CommonJS | ESM |
|---|---|---|
| Sintaksis | require, module.exports |
import, export |
| Yuklash | sinxron, dinamik | asinxron, statik |
| Vaqti | run-time | compile-time (hoisted) |
| Tree-shaking | qiyin | oson (statik) |
this (top-level) |
module.exports |
undefined |
| Import qiymati | nusxa | jonli havola (live binding) |
// CommonJS
const fs = require("fs");
module.exports = { foo };
// ESM
import fs from "fs";
export const foo = () => {};
export default main;
const modul = await import("./dinamik.js"); // dinamik import Tuzoq. ESM'da import hoisted va statik — uni if ichida shartli yoza olmaysiz (buning uchun dinamik import()). ESM'da import qiymati live binding — eksport qiluvchi modulda o'zgarsa, import qilgan yerda ham o'zgaradi (CommonJS'da nusxa).
Follow-up. "Tree-shaking nima va nega ESM'da oson?" · "Live binding nima?" · "Node'da .mjs va "type":"module" farqi?"
S: IIFE nima va nima uchun ishlatilgan? (Middle)
J: Ta'rif. IIFE (Immediately Invoked Function Expression) — e'lon qilinishi bilanoq darrov chaqiriladigan funksiya ifodasi.
Mexanizm. Funksiya qavs ichiga olinib ((function(){})) ifodaga aylantiriladi, keyin () bilan darrov chaqiriladi. Bu alohida scope yaratadi — ichidagi o'zgaruvchilar global'ni "ifloslantirmaydi" (namespace himoyasi).
(function () {
var maxfiy = "tashqaridan ko'rinmaydi";
console.log("Darrov ishladi");
})();
// Arrow bilan
(() => {
const x = 10;
})();
// Modul pattern — private + public
const hisoblagich = (function () {
let count = 0; // private
return {
oshir: () => ++count,
ol: () => count,
};
})();
hisoblagich.oshir();
console.log(hisoblagich.ol()); // 1Tarixiy sabab: ES6'gacha let/const va modul yo'q edi — IIFE global scope ifloslanishining oldini olish va private holat yaratishning yagona usuli edi.
Tuzoq. Bugungi kunda ESM va blok scope (let/const) IIFE'ning ko'p vazifasini bajaradi — shuning uchun yangi kodda kam uchraydi. Lekin bundle'lar, polyfill'lar hali ishlatadi.
Follow-up. "Nega qavs kerak?" (ifoda qilish uchun) · "Module pattern nima?" · "Bugun IIFE o'rniga nima?" (ESM, blok scope).
S: class — private maydonlar, static, getter/setter qanday ishlaydi? (Senior)
J: Ta'rif. class — prototypal meros ustidagi sintaktik shakar (yangi mexanizm emas). Ichida u hali prototype bilan ishlaydi, lekin zamonaviy imkoniyatlar qo'shadi.
Mexanizm.
- Private maydon (
#field) — faqat class ichida ko'rinadi, tashqaridan haqiqiy yopiq (til darajasida). - Static — nusxada emas, class'ning o'zida yashaydigan metod/maydon.
- Getter/setter — property'dek ko'rinadigan, lekin funksiya ishga tushiradigan.
class HisobRaqam {
#balans = 0; // private
static bank = "MilliyBank"; // static maydon
constructor(boshlangich) {
this.#balans = boshlangich;
}
get balans() { // getter — obj.balans (qavssiz)
return `${this.#balans} so'm`;
}
set balans(qiymat) { // setter — validatsiya bilan
if (qiymat < 0) throw new Error("Manfiy bo'lmaydi");
this.#balans = qiymat;
}
#ichkiHisob() { return this.#balans * 0.1; } // private metod
static ochish(summa) { // static — HisobRaqam.ochish()
return new HisobRaqam(summa);
}
}
const h = HisobRaqam.ochish(1000);
console.log(h.balans); // "1000 so'm" (getter)
h.balans = 5000; // setter
// console.log(h.#balans); // SyntaxError — private Tuzoq. #private — haqiqiy yopiq (eski _convention faqat kelishuv edi). Static metodda this — class'ning o'zi, nusxa emas. Va getter/setter'ni bir xil nom bilan yozing, aks holda biri ustuvor bo'ladi.
Follow-up. "#private va _private farqi?" · "Static metodda this nima?" · "class ostida nima yotadi?" (prototype) · "super qanday ishlaydi?"
S: Event delegation nima? Nima uchun foydali? (Middle)
J: Ta'rif. Event delegation — ko'p bola elementga alohida listener qo'yish o'rniga, bitta ota (parent) elementga listener qo'yib, event'ni bubbling orqali ushlab, event.target bilan qaysi bola bosilganini aniqlash.
Mexanizm. DOM eventlari (masalan click) bolada sodir bo'lgach, ota-bobolarga qarab "ko'tariladi" (bubble). Ota listener shu bubbling'ni ushlaydi. Bu — kam listener (tez, kam xotira) va dinamik qo'shilgan bolalar ham avtomatik ishlaydi (yangi listener kerak emas).
// Har element uchun alohida — dinamik qo'shilsa ishlamaydi
document.querySelectorAll("li").forEach((li) =>
li.addEventListener("click", handle)
);
// Bitta listener otada — delegation
document.querySelector("ul").addEventListener("click", (e) => {
const li = e.target.closest("li");
if (li) console.log("Bosildi:", li.textContent);
});
// Endi yangi <li> qo'shilsa ham avtomatik ishlaydi Tuzoq. event.target — aynan bosilgan (eng ichki) element; event.currentTarget — listener biriktirilgan element (ota). Nested elementlar bo'lsa, closest() bilan to'g'ri bolaga ko'tarilish kerak, aks holda ichki <span> bosilsa target u bo'ladi.
Follow-up. "target va currentTarget farqi?" · "Bubbling va capturing farqi?" · "stopPropagation nima qiladi?" · "Nega dinamik ro'yxatlarda foydali?"
S: NaN nima? NaN === NaN nega false? (Middle — tuzoq)
J: Ta'rif. NaN (Not-a-Number) — noto'g'ri/aniqlanmagan matematik amal natijasi (0/0, parseInt("abc"), Math.sqrt(-1)). U number turida (typeof NaN === "number"), lekin hech bir aniq songa teng emas.
Mexanizm. IEEE 754 standarti bo'yicha NaN o'ziga ham teng emas — chunki u "aniqlanmagan qiymat"; ikki noaniqlik teng bo'la olmaydi. Shuning uchun NaN === NaN false.
console.log(NaN === NaN); // false
console.log(0 / 0); // NaN
console.log(parseInt("salom")); // NaN
console.log(typeof NaN); // "number"
// NaN'ni to'g'ri aniqlash
console.log(Number.isNaN(NaN)); // true — tavsiya etiladi
console.log(isNaN("abc")); // true — lekin coercion qiladi (xavfli)
console.log(Number.isNaN("abc"));// false — string NaN emas, aniq
console.log(Object.is(NaN, NaN));// true — Object.is buni to'g'ri ko'radi Tuzoq. Global isNaN() avval qiymatni songa aylantiradi — isNaN("abc") true (chunki Number("abc") = NaN), noto'g'ri natija berishi mumkin. Number.isNaN() ishlating — u coercion qilmaydi. NaNni === bilan tekshirib bo'lmaydi.
Follow-up. "isNaN va Number.isNaN farqi?" · "Object.is nima?" · "NaNni massivda indexOf topa oladimi?" (yo'q — === ishlatadi; includes topadi).
S: undefined va null orasidagi farq nima? (Middle)
J: Ta'rif.
undefined— o'zgaruvchi e'lon qilingan, lekin qiymat berilmagan (JS avtomatik beradi).null— atayin "qiymat yo'q" deb belgilangan (dasturchi qo'yadi).
Mexanizm. undefined — "hali aniqlanmagan" (tizim holati): e'lon qilingan-u biriktirilmagan o'zgaruvchi, mavjud bo'lmagan obyekt propertysi, returnsiz funksiya natijasi. null — "ataylab bo'sh" (dasturchining niyati).
let a;
console.log(a); // undefined — qiymat berilmagan
console.log({}.yoq); // undefined — property yo'q
console.log((() => {})()); // undefined — return yo'q
let b = null; // atayin bo'sh
console.log(b); // null
// Taqqoslash
console.log(null == undefined); // true — coercion
console.log(null === undefined); // false — turlar farqli
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (bug) Tuzoq. typeof null "object" (tarixiy bug), typeof undefined "undefined". null == undefined true, lekin === false. JSON.stringify undefinedni tashlab yuboradi, nullni saqlaydi.
Follow-up. "Qay birini o'zingiz qo'yasiz?" (null) · "JSON.stringify ikkalasini qanday ko'radi?" · "Default parametr nullda ishlaydimi?" (yo'q — faqat undefinedda).
S: slice va splice farqi nima? (Junior — chalkashtiruvchi)
J: Ta'rif.
slice— massivning bir qismini nusxalab oladi, aslini o'zgartirmaydi (immutable).splice— massiv ichidan element o'chiradi/qo'shadi, aslini o'zgartiradi (mutable).
const arr = [1, 2, 3, 4, 5];
// slice(start, end) — end kirmaydi, asl saqlanadi
console.log(arr.slice(1, 3)); // [2, 3]
console.log(arr); // [1,2,3,4,5] — o'zgarmadi
// splice(start, deleteCount, ...qoshiladigan) — aslini o'zgartiradi
const arr2 = [1, 2, 3, 4, 5];
const olingan = arr2.splice(1, 2, "a", "b"); // 2 tani o'chir, a,b qo'sh
console.log(olingan); // [2, 3] — o'chirilganlar
console.log(arr2); // [1, "a", "b", 4, 5] — o'zgardi (mutatsiya) Tuzoq. splice mutatsiya qiladi — React state kabi joyda to'g'ridan-to'g'ri ishlatmang (immutability buziladi). Nom o'xshash, ish teskari — chalkashtirmang. slice xavfsiz nusxa uchun.
Follow-up. "Qay biri asl massivni o'zgartiradi?" (splice) · "React'da qay birini ishlatasiz?" (slice/spread) · "Nusxa olishning boshqa usullari?" ([...arr], Array.from).
S: forEach, for...of, for...in farqi nima? (Middle)
J: Ta'rif.
forEach— massiv metodi, har elementga callback;break/returnbilan to'xtatib bo'lmaydi.for...of— qiymatlar bo'ylab yuradi (iterable: massiv, string, Map, Set);break/continueishlaydi.for...in— obyekt kalitlari (key/index) bo'ylab yuradi, meros kalitlarni ham oladi.
const arr = ["a", "b", "c"];
arr.forEach((v, i) => console.log(i, v)); // 0 a, 1 b, 2 c — to'xtatib bo'lmaydi
for (const v of arr) { // qiymatlar
if (v === "b") break; // break ishlaydi
console.log(v); // "a"
}
for (const k in arr) console.log(k); // "0","1","2" — indekslar (string!)
// for...in obyektga
const obj = { x: 1, y: 2 };
for (const key in obj) console.log(key, obj[key]); Tuzoq. for...inni massivga ishlatmang — indekslar string bo'ladi, meros propertylar ham kiradi, tartib kafolatlanmasligi mumkin. Massivga — for...of yoki forEach. forEach ichida await kutmaydi (asinxron kod uchun for...of ishlating).
Follow-up. "for...inni nega massivda ishlatmaslik kerak?" · "forEachni async bilan ishlata olasizmi?" (yo'q — kutmaydi) · "break qay birlarida ishlaydi?"
S: Pure function nima? Side effect-chi? (Senior)
J: Ta'rif.
- Pure function — (1) bir xil kirishga har doim bir xil chiqish beradigan, (2) side effect'siz funksiya.
- Side effect — funksiya o'z scope'idan tashqaridagi holatni o'zgartirishi (global o'zgaruvchi, DOM, tarmoq, fayl, argumentni mutatsiya, console).
Mexanizm. Pure function tashqi dunyoga bog'liq emas va uni o'zgartirmaydi — shuning uchun bashoratli, test qilish oson, memoize qilinadi, parallel ishlashi xavfsiz. Bu — funksional dasturlash va React/Redux'ning asosi.
// Pure — bir xil kirish bir xil chiqish, side effect yo'q
function qoshish(a, b) { return a + b; }
function ikkiBaravar(arr) { return arr.map((x) => x * 2); } // yangi massiv
// Impure — tashqi holatni o'zgartiradi
let jami = 0;
function qoshImpure(x) { jami += x; return jami; } // global mutatsiya (side effect)
function mutatsiya(arr) { arr.push(1); return arr; } // argumentni buzadi Tuzoq. Argument sifatida olingan obyekt/massivni mutatsiya qilish — yashirin side effect (havola bir edi, eslang!). Toza funksiya yangi qiymat qaytarishi kerak. Math.random(), Date.now() — pure emas (har safar boshqa natija).
Follow-up. "React komponenti nega pure bo'lishi kerak?" · "Memoization qanday pure'lik'ga tayanadi?" · "Side effect'larni qayerda joylashtirasiz?" (chetga — useEffect, action).
S: Object.freeze nima qiladi? Chuqurmi? (Middle)
J: Ta'rif. Object.freeze(obj) — obyektni o'zgarmas (immutable) qiladi: yangi property qo'shib, borini o'chirib yoki o'zgartirib bo'lmaydi. Lekin bu faqat bir daraja (shallow) chuqurlikda.
Mexanizm. Freeze qilingan obyektga yozish strict mode'da xato, sloppy mode'da jimgina e'tiborsiz qoldiriladi. Ichki (nested) obyektlar muzlatilmaydi — ular hali o'zgaradi.
const config = Object.freeze({
ism: "app",
sozlama: { tema: "dark" },
});
config.ism = "boshqa"; // jimgina e'tiborsiz (strict'da xato)
console.log(config.ism); // "app" — o'zgarmadi
config.sozlama.tema = "light"; // ISHLAYDI — ichki obyekt muzlamagan!
console.log(config.sozlama.tema); // "light"
console.log(Object.isFrozen(config)); // true
// Deep freeze — rekursiv
function deepFreeze(obj) {
Object.keys(obj).forEach((k) => {
if (typeof obj[k] === "object" && obj[k] !== null) deepFreeze(obj[k]);
});
return Object.freeze(obj);
} Tuzoq. Object.freeze shallow — nested obyektlar himoyalanmagan. To'liq immutability uchun rekursiv deepFreeze yoki Immutable.js/Immer kerak.
Follow-up. "Freeze deep'mi shallow'mi?" (shallow) · "freeze va const farqi?" (const — binding, freeze — mazmun) · "Object.seal nima?" (o'zgartirish mumkin, qo'shib/o'chirib bo'lmaydi).
S: setTimeout(fn, 0) haqiqatan 0ms da ishlaydimi? (Middle — tuzoq)
J: Javob: Yo'q. setTimeout(fn, 0) "darrov" degani emas — u callback'ni macrotask navbatiga qo'yadi, va u faqat (1) joriy sinxron kod tugab, (2) barcha microtasklar bajarilgach ishga tushadi.
Mexanizm. Timer tugagach callback to'g'ridan-to'g'ri chaqirilmaydi — macrotask queue'ga tushadi. Event loop stack bo'shashini, microtask'lar tozalanishini kutadi. Bundan tashqari, brauzer spetsifikatsiyasi ichma-ich (nested) timerlarga minimal 4ms cheklovi qo'yadi.
console.log("1");
setTimeout(() => console.log("2"), 0); // macrotask — oxirida
Promise.resolve().then(() => console.log("3")); // microtask — 2'dan oldin
console.log("4");
// Chiqish: 1, 4, 3, 2 — "2" oxirida, garchi 0ms bo'lsa hamAmaliy foyda: setTimeout(fn, 0) og'ir ishni "keyingi tick"ga surib, UI'ni bloklamaslik uchun ishlatiladi (yield to event loop).
Tuzoq. setTimeout(fn, 0)ga "sinxron ketma-ketlikni buzish" yoki "aniq 0ms kechikish" uchun tayanmang. U faqat "hozirgi ishlar tugagach, imkon bo'lganda" ishlaydi — vaqt kafolatlanmagan.
Follow-up. "Nega darrov emas?" (macrotask) · "Microtask'dan oldin yoki keyin?" (keyin) · "setTimeout va queueMicrotask farqi?" · "4ms cheklovi nima?"
S: Memoization nima? Qanday yozasiz? (Senior)
J: Ta'rif. Memoization — funksiya natijalarini keshlab, bir xil argument bilan qayta chaqirilganda hisoblamasdan keshdan qaytarish optimizatsiyasi. Faqat pure funksiyalarda ishonchli.
Mexanizm. Argument(lar)dan kalit yasab, natijani Map/obyektda saqlaydi. Keyingi chaqiruvda kalit mavjud bo'lsa — hisoblashni o'tkazib yuborib, keshdan beradi. Bu — takroriy og'ir hisoblarni (rekursiya, API) tezlashtiradi.
function memoize(fn) {
const kesh = new Map();
return function (...args) {
const kalit = JSON.stringify(args);
if (kesh.has(kalit)) return kesh.get(kalit); // keshdan
const natija = fn.apply(this, args);
kesh.set(kalit, natija);
return natija;
};
}
// Og'ir hisob — fibonachchi
const fib = memoize(function (n) {
return n < 2 ? n : fib(n - 1) + fib(n - 2);
});
console.log(fib(40)); // tez — takroriy shoxlar keshlanadi Tuzoq. JSON.stringify kalit sifatida cheklovli — funksiya, undefined, kalitlar tartibi bilan muammo. Va kesh cheksiz o'sishi memory leak beradi (LRU cheklov kerak). Faqat pure funksiyani memoize qiling — impure'da eski/noto'g'ri natija qaytadi.
Follow-up. "Nima uchun faqat pure funksiya?" · "Kesh cheksiz o'ssa nima bo'ladi?" (leak) · "React useMemo/React.memo shu tamoyilmi?" (ha) · "LRU cache nima?"
S: JSON.stringify va JSON.parse nima? Cheklovlari? (Middle)
J: Ta'rif.
JSON.stringify(obj)— JS qiymatini JSON stringga aylantiradi (serializatsiya).JSON.parse(str)— JSON string'ni JS obyektga qaytaradi (deserializatsiya).
Mexanizm. stringify obyektni rekursiv aylanib, JSON matnini quradi. Ba'zi turlarni qo'llab-quvvatlamaydi yoki yo'qotadi.
const obj = {
ism: "Ali",
yosh: 25,
metod: () => {}, // yo'qoladi
qiymat: undefined, // yo'qoladi
sana: new Date(), // string'ga aylanadi
belgi: Symbol("s"), // yo'qoladi
nan: NaN, // null bo'ladi
};
console.log(JSON.stringify(obj));
// {"ism":"Ali","yosh":25,"sana":"2026-...","nan":null}
// 2-argument (replacer) va 3-argument (chiroyli chiqarish)
console.log(JSON.stringify({ a: 1, b: 2 }, null, 2)); // 2 probel indent
console.log(JSON.stringify(obj, ["ism"])); // faqat "ism" Tuzoq. stringify yo'qotadi: funksiya, undefined, Symbol (tashlab yuboriladi); NaN/Infinity null; Date ISO string; sirkulyar havola xato tashlaydi. Shuning uchun deep copy uchun ham xavfli (yuqoridagi savolga qarang).
Follow-up. "Sirkulyar havolani stringify qilsangiz nima bo'ladi?" (TypeError) · "replacer va reviver nima?" · "toJSON metodi nima qiladi?"
S: Event bubbling va capturing nima? (Middle)
J: Ta'rif. DOM event bir elementda sodir bo'lganda ikki fazadan o'tadi:
- Capturing (tushish) — event
documentdan boshlab pastga, nishon elementgacha tushadi. - Bubbling (ko'tarilish) — nishondan boshlab yuqoriga,
documentgacha ko'tariladi.
Mexanizm. Standart bo'yicha listener'lar bubbling fazasida ishlaydi. addEventListenerning uchinchi argumenti true bo'lsa — capturing fazasida. To'liq yo'l: capture (yuqoridan) target bubble (yuqoriga).
// Bubbling (default) — ichkaridan tashqariga
parent.addEventListener("click", () => console.log("parent"));
child.addEventListener("click", () => console.log("child"));
// Child bosilsa: "child" "parent"
// Capturing — tashqaridan ichkariga
parent.addEventListener("click", () => console.log("parent-capture"), true);
// Child bosilsa: "parent-capture" "child"
// To'xtatish
child.addEventListener("click", (e) => {
e.stopPropagation(); // bubbling to'xtaydi — parent eshitmaydi
}); Tuzoq. stopPropagation() event tarqalishini to'xtatadi (boshqa listenerlar), preventDefault() esa standart brauzer harakatini (link ochilishi, form submit) to'xtatadi — ular boshqa narsa. Aralashtirmang. Ba'zi eventlar (focus, scroll) bubble bo'lmaydi.
Follow-up. "stopPropagation va preventDefault farqi?" · "Event delegation qay fazaga tayanadi?" (bubbling) · "Qaysi eventlar bubble bo'lmaydi?"
S: apply va call bilan Math.maxni massivga qanday qo'llaysiz? (Senior — amaliy)
J: Ta'rif. Math.max alohida argumentlar oladi (Math.max(1, 2, 3)), massiv emas. Massivdan max topish uchun elementlarni argumentlarga yoyish kerak.
const sonlar = [5, 1, 8, 3];
// Eski usul — apply (massivni argumentlarga yoyadi)
console.log(Math.max.apply(null, sonlar)); // 8
// Zamonaviy — spread
console.log(Math.max(...sonlar)); // 8
// Katta massivda spread xavfi — stack overflow
const juda_katta = new Array(200000).fill(1);
// Math.max(...juda_katta); // RangeError bo'lishi mumkin
console.log(juda_katta.reduce((m, x) => Math.max(m, x), -Infinity)); // xavfsizMexanizm. apply(null, arr) — arr elementlarini funksiyaga alohida argument qilib uzatadi. Spread (...arr) — xuddi shu, lekin zamonaviy va o'qishli.
Tuzoq. Juda katta massivda Math.max(...arr) yoki apply — argument soni chegarasidan oshib, stack overflow (RangeError) berishi mumkin (~10⁵–10⁶). Bunda reduce ishlating.
Follow-up. "Spread va apply farqi?" · "Katta massivda nega xato?" · "Bo'sh massivda Math.max() nima?" (-Infinity).
Eng ko'p so'raladigan 10 savol
Vaqtingiz kam bo'lsa, avval shularni mukammal o'zlashtiring — bu 10 tasi deyarli har bir JavaScript intervyusida chiqadi:
var/let/constva hoisting + TDZ — deyarli har suhbatning birinchi savoli. Block vs function scope, TDZ'ni aniq ayting.- Closure — nima, qanday ishlaydi, amaliy foyda (private holat, hooks). Loop +
setTimeouttuzog'ini biling. thisva call/apply/bind — 5 chaqiruv qoidasi + arrow farqi. "Nuqtasiz chaqiruvdathisyo'qoladi" — kalit tushuncha.- Event loop (call stack, microtask vs macrotask) — Senior savoli. Kod chiqishi tartibini tushuntira olish shart.
- Promise + async/await — holatlar,
.all/race/allSettled/any,try/catch, ketma-ket vs parallel. - Prototype va prototypal inheritance —
__proto__vsprototype,newichida nima bo'ladi. ==vs===+ coercion + falsy qiymatlar —[] == false,null == undefinedkabi tuzoqlar.[1,2,3].map(parseInt)— klassik tuzoq ([1, NaN, NaN]).map3 argument uzatishini biling.- Debounce va throttle — kod bilan yozib bera olish (Senior). Qay biri qayerda ishlatilishi.
0.1 + 0.2 !== 0.3vatypeof null === "object"— mashhur "gotcha"'lar; sababini (IEEE 754, tarixiy bug) tushuntiring.
Yakuniy maslahat: Intervyuchi javobingizdan keyin deyarli har doim "nega?" yoki "ichida qanday ishlaydi?" deb so'raydi. Shuning uchun har savolning Mexanizm va Follow-up qismini ham tayyorlang — aynan shu chuqurlik sizni junior'dan middle/senior'ga ajratadi. Yodlamang — tushuning va o'z so'zingiz bilan gapiring.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!