Pure funksiyalar va Side Effects

~15 daq · JavaScript · Funksiyalar chuqurroq

Muammodan boshlaylik

let jami = 0;

function qoshish(son) {
  jami += son; // ← tashqi o'zgaruvchini o'zgartiradi
  return jami;
}

qoshish(5); // 5
qoshish(5); // 10 — bir xil argument, boshqa natija!

Bir xil argument — boshqa natija. Bu funksiyani test qilish, tushunish, qayta ishlatish qiyinlashadi. Pure funksiya bu muammoni hal qiladi.


Pure funksiya nima?

Pure funksiya — ikkita qoidaga amal qiladi:

  1. Bir xil argument → har doim bir xil natija
  2. Yon ta'sir (side effect) yo'q — tashqi hech narsani o'zgartirmaydi
// Pure funksiya
function qoshish(a, b) {
  return a + b; // ← faqat parametrlarga bog'liq, hech narsani o'zgartirmaydi
}

qoshish(3, 5); // 8 — har doim
qoshish(3, 5); // 8 — har doim

Hayotiy o'xshatma

Kalkulyator. Siz "3 + 5" bosasangiz — har doim "8" chiqadi. Oldingi hisoblashlar ta'sir qilmaydi. Kalkulyator tashqi hech narsani o'zgartirmaydi — faqat hisoblaydi va ko'rsatadi.

Pure funksiya — dasturlashdagi kalkulyator.


Side Effect nima?

Side effect — funksiyaning o'z qaytish qiymatidan tashqari qiladigan har qanday ish:

// Side effect turlari:
function misol(x) {
  console.log(x);           // ← side effect: konsolga yozish
  document.title = "Yangi"; // ← side effect: DOM o'zgartirish
  globalVar = x;            // ← side effect: tashqi o'zgaruvchi o'zgartirish
  fetch("/api/log");        // ← side effect: tarmoq so'rovi
  return x * 2;
}

Side effect — yomon emas. Dastur side effectsiz ishlamaydi — ma'lumot saqlanmaydi, ekranda hech narsa ko'rinmaydi. Lekin side effectlar nazorat ostida bo'lishi kerak.


Nima uchun pure funksiyalar yaxshi?

Bashorat qilish mumkin

// Pure — natijani oldindan bilasiz
const natija = qoshish(3, 5); // har doim 8

Test qilish oson

// Pure funksiyani test qilish — oddiy
test("qoshish to'g'ri ishlaydi", () => {
  expect(qoshish(3, 5)).toBe(8);
  expect(qoshish(-1, 1)).toBe(0);
});
// Hech qanday mock, setup kerak emas

Qayta ishlatish mumkin

Pure funksiya hech narsaga bog'liq emas — istalgan joyda ishlatiladi.


Impure funksiyalar — qachon muammo?

// Tashqi holatga bog'liq — impure
let chegirma = 0.1;

function narxHisoblash(narx) {
  return narx * (1 - chegirma); // ← chegirma tashqarida
}

narxHisoblash(100); // 90
chegirma = 0.2;
narxHisoblash(100); // 80 — bir xil argument, boshqa natija!

Yechim — chegirmani parametr sifatida berish:

// Pure
function narxHisoblash(narx, chegirma) {
  return narx * (1 - chegirma);
}

narxHisoblash(100, 0.1); // 90 — har doim
narxHisoblash(100, 0.2); // 80 — har doim

Massiv va ob'ektlar bilan ehtiyotkorlik

Massiv va ob'ektlar — reference type. Funksiya ichida o'zgartirilsa — tashqaridagi asl qiymat ham o'zgaradi:

// Impure — asl massivni o'zgartiradi
function birinchiniOchir(massiv) {
  massiv.shift(); // ← asl massivni o'zgartiradi!
  return massiv;
}

const sonlar = [1, 2, 3];
birinchiniOchir(sonlar);
console.log(sonlar); // [2, 3] — asl massiv o'zgardi!

Pure variant — yangi massiv qaytarish:

// Pure — yangi massiv qaytaradi
function birinchiniOchir(massiv) {
  return massiv.slice(1); // ← yangi massiv, asl o'zgarmaydi
}

const sonlar = [1, 2, 3];
const yangi = birinchiniOchir(sonlar);
console.log(sonlar); // [1, 2, 3] — o'zgarmadi
console.log(yangi);  // [2, 3]

Amalda qanday yozish kerak?

Hamma funksiyani pure qilish shart emas — lekin pure va impure ni ajratish kerak:

// Pure — hisoblash mantiq
function jami_hisoblash(buyurtmalar) {
  return buyurtmalar.reduce((sum, b) => sum + b.narx, 0);
}

// Impure — side effect (ma'lumot olish, saqlash)
async function buyurtmalarniSaqla(buyurtmalar) {
  const jami = jami_hisoblash(buyurtmalar); // ← pure funksiyani chaqiradi
  await db.save({ buyurtmalar, jami });
}

Pure funksiyalar — mantiq uchun. Impure funksiyalar — tashqi dunyo bilan ishlash uchun.


Tez-tez uchraydigan xatolar

Ob'ektni to'g'ridan-to'g'ri o'zgartirish:

function yangilash(foydalanuvchi, yangiIsm) {
  foydalanuvchi.ism = yangiIsm; // ❌ asl ob'ekt o'zgardi
  return foydalanuvchi;
}

// ✅ yangi ob'ekt qaytarish
function yangilash(foydalanuvchi, yangiIsm) {
  return { ...foydalanuvchi, ism: yangiIsm };
}

Tashqi o'zgaruvchiga bog'liqlik:

const soliq = 0.12;

function narx(asosiy) {
  return asosiy * (1 + soliq); // ❌ tashqi soliq ga bog'liq
}

function narx(asosiy, soliq) {
  return asosiy * (1 + soliq); // ✅ parametr sifatida
}

Xulosa

Pure funksiya — bir xil argument → har doim bir xil natija, side effect yo'q.

Side effect — tashqi o'zgaruvchi o'zgartirish, DOM, tarmoq, konsol. Yomon emas — lekin nazorat ostida bo'lishi kerak.

Pure funksiyalar — bashorat qilish mumkin, test qilish oson, qayta ishlatish mumkin.

Massiv va ob'ektlarni o'zgartirish o'rniga — yangi nusxa qaytariladi (slice, map, spread ...).


Keyingi dars

15-dars: Recursion — o'z-o'zini chaqirish