Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Domknięcia w programowaniu funkcyjnym

W Parku Jurajskim każdy wybieg ma swój własny system zabezpieczeń - napięcie ogrodzenia, poziom alarmowy, licznik incydentów. Te dane są prywatne i niedostępne z zewnątrz, ale funkcje zarządzające wybiegiem mają do nich pełny dostęp. Dokładnie tak działają domknięcia (closures) - tworzą prywatne środowisko dla danych, dostępne tylko przez określone funkcje.

Czym jest domknięcie?

Domknięcie (closure) to funkcja, która "pamięta" zmienne z zakresu (scope), w którym została stworzona, nawet po tym, jak ten zakres przestał istnieć.

1function createCounter() {
2  let count = 0; // Zmienna prywatna - niedostepna z zewnatrz
3
4  return {
5    increment() { count++; return count; },
6    decrement() { count--; return count; },
7    getCount() { return count; },
8  };
9}
10
11const counter = createCounter();
12counter.increment(); // 1
13counter.increment(); // 2
14counter.getCount();  // 2
15// count jest calkowicie prywatna - nie ma do niej bezposredniego dostepu

Prywatność danych przez domknięcia

Domknięcia pozwalają tworzyć prawdziwie prywatne zmienne w JavaScript - to kluczowy wzorzec w programowaniu funkcyjnym:

1function createSecuritySystem(zoneName) {
2  let fenceVoltage = 10000;
3  let alertLevel = 0;
4  let incidentLog = [];
5
6  // Prywatna funkcja pomocnicza
7  function logEvent(event) {
8    incidentLog.push({ event, time: Date.now(), zone: zoneName });
9  }
10
11  return {
12    raiseFence() {
13      fenceVoltage += 2000;
14      logEvent('Fence voltage raised to ' + fenceVoltage);
15      return fenceVoltage;
16    },
17    triggerAlert() {
18      alertLevel++;
19      logEvent('Alert level: ' + alertLevel);
20      return alertLevel;
21    },
22    getStatus() {
23      return {
24        zone: zoneName,
25        voltage: fenceVoltage,
26        alert: alertLevel,
27        incidents: incidentLog.length,
28      };
29    },
30  };
31}
32
33const zoneA = createSecuritySystem('Zone A');
34const zoneB = createSecuritySystem('Zone B');
35
36zoneA.raiseFence();  // 12000
37zoneA.triggerAlert(); // 1
38zoneB.getStatus();   // { zone: 'Zone B', voltage: 10000, alert: 0, incidents: 0 }
39// Kazda strefa ma wlasne, izolowane dane

Fabryki funkcji (Function Factories)

Domknięcia są idealne do tworzenia fabryk - funkcji, które produkują wyspecjalizowane funkcje:

1// Fabryka walidatorow
2function createValidator(rules) {
3  return function validate(data) {
4    const errors = [];
5    for (const [field, rule] of Object.entries(rules)) {
6      if (rule.required && !data[field]) {
7        errors.push(field + ' is required');
8      }
9      if (rule.min && data[field] < rule.min) {
10        errors.push(field + ' must be >= ' + rule.min);
11      }
12      if (rule.max && data[field] > rule.max) {
13        errors.push(field + ' must be <= ' + rule.max);
14      }
15    }
16    return { valid: errors.length === 0, errors };
17  };
18}
19
20const validateDinosaur = createValidator({
21  name: { required: true },
22  weight: { required: true, min: 1, max: 100000 },
23  health: { required: true, min: 0, max: 100 },
24});
25
26validateDinosaur({ name: 'Rex', weight: 8000, health: 95 });
27// { valid: true, errors: [] }
28
29validateDinosaur({ name: '', weight: -5, health: 150 });
30// { valid: false, errors: ['name is required', 'weight must be >= 1', 'health must be <= 100'] }

Memoizacja z domknięciami

Memoizacja to technika cachowania wyników kosztownych obliczeń. Domknięcia zapewniają prywatny cache:

1function memoize(fn) {
2  const cache = new Map();
3
4  return function(...args) {
5    const key = JSON.stringify(args);
6    if (cache.has(key)) {
7      console.log('Cache hit for:', key);
8      return cache.get(key);
9    }
10    const result = fn(...args);
11    cache.set(key, result);
12    return result;
13  };
14}
15
16// Kosztowna analiza DNA
17function analyzeDNA(sampleId, depth) {
18  // Symulacja dlugiego obliczenia
19  let result = 0;
20  for (let i = 0; i < depth * 1000; i++) {
21    result += Math.random();
22  }
23  return { sampleId, score: result / (depth * 1000) };
24}
25
26const memoizedAnalyze = memoize(analyzeDNA);
27memoizedAnalyze('TREX-001', 100); // oblicza
28memoizedAnalyze('TREX-001', 100); // z cache - natychmiastowo!
Przejdź do CodeWorlds