Function declaration, function expression va strelka funksiya bir-biridan nimasi bilan farq qiladi?

JuniorJavaScript #javascript #functions

Savol

Funksiya e'loni (function declaration), funksional ifoda (function expression) va strelka funksiya o'rtasidagi farq nimada — ayniqsa hoisting va this kontekstida?

Qisqa javob

Function declaration to'liq ko'tariladi (hoisting) va e'lon qilingan qatorgacha ham mavjud bo'ladi. Function expression faqat o'zgaruvchi sifatida ko'tariladi (qiymatsiz) yoki const/let orqali e'lon qilingan bo'lsa, umuman ko'tarilmaydi. Ikkalasi ham o'z this va argumentsiga ega. Strelka funksiya chaqiriladigan funksiya sifatida ko'tarilmaydi, o'z this, arguments va superiga ega emas — ularni tashqi ko'rinish sohasidan oladi.

Batafsil javob

Function declaration — function foo() {}. Dvigatel bunday e'lonlarni kod qator-qator bajarilishidan oldin, ko'rinish sohasini yaratish bosqichida qayta ishlaydi, shuning uchun funksiyani kodda uning e'lonidan yuqorida chaqirish mumkin.

Function expression — o'zgaruvchiga o'zlashtirilgan funksiya: const foo = function() {} (anonim yoki nomlangan bo'lishi mumkin). Bu yerda faqat o'zgaruvchi ko'tariladi (var foo → undefined, let/const foo → temporal dead zone), lekin funksiyaning o'zi qiymat sifatida ko'tarilmaydi. Uni o'zlashtirish qatoridan oldin chaqirib bo'lmaydi.

Strelka funksiya — const foo = () => {} — bu har doim ifoda (expression), hech qachon e'lon (declaration) emas. Asosiy farq hoisting'da emas, xatti-harakatda:

  • O'z thisiga ega emas — uni leksik jihatdan, yaratilgan paytdagi o'rab turuvchi koddan oladi.
  • O'z arguments obyektiga ega emas — murojaat qilinganda tashqi funksiyaning argumentsi olinadi (yoki u bo'lmasa xato).
  • Konstruktor sifatida ishlatib bo'lmaydi (new (() => {})() TypeError tashlaydi).
  • prototypega ega emas.
  • thisni o'zgartirish uchun bind/call/apply orqali bog'lab bo'lmaydi.

Amaliy qoida: oddiy funksiyalarni (function) obyekt metodlari uchun va dinamik this kerak bo'lgan joylarda ishlatish kerak (masalan, DOM elementlaridagi hodisa ishlovchilarida, bu yerda this elementning o'zi bo'lishi kerak). Strelka funksiyalarni — tashqi kontekstning thisini saqlab qolish kerak bo'lgan callback'lar uchun (masalan, klass metodlari yoki React komponentlari ichida).

Strelka funksiyalardagi this xatti-harakatining batafsil tahlili — alohida mavzu, bu yerda faqat shu muhim: strelka funksiya o'z kontekstini yaratmaydi, balki tashqisini "shaffof" ravishda ishlatadi.

Misol

// Hoisting: declaration e'lon qilinguncha ham ishlaydi
console.log(sum(2, 3)) // 5 — ishlaydi
function sum(a, b) {
  return a + b
}

// Function expression: o'zlashtirilguncha TDZ / undefined
console.log(typeof multiply) // "undefined" (var) — o'zgaruvchi ko'tarilgan, qiymati yo'q
var multiply = function (a, b) {
  return a * b
}

// console.log(divide()) // ReferenceError: Cannot access 'divide' before initialization
const divide = (a, b) => a / b

// Oddiy funksiyaning o'z this'i vs strelkaning leksik this'i
const counter = {
  value: 0,
  incRegular: function () {
    setTimeout(function () {
      // bu yerdagi this — counter emas (qat'iy rejimda undefined)
      console.log(this === counter) // false
    }, 0)
  },
  incArrow: function () {
    setTimeout(() => {
      // strelka this'ni incArrow'dan oladi, u yerda esa this === counter
      console.log(this === counter) // true
    }, 0)
  },
}
counter.incRegular()
counter.incArrow()

// arguments: oddiy funksiyada bor, strelkada yo'q
function regular() {
  return arguments.length
}
console.log(regular(1, 2, 3)) // 3

const arrow = (...args) => args.length // strelka arguments'ni shunday taqlid qiladi
console.log(arrow(1, 2, 3)) // 3

Qo'shimcha savollar

  • Nega strelka funksiyani new bilan konstruktor sifatida ishlatib bo'lmaydi?
  • Temporal dead zone nima va u let/const hoisting'i bilan qanday bog'liq?
  • Strelka funksiya sifatida e'lon qilingan obyekt metodi thisning kutilgan xatti-harakatini qanday buzadi?