Heim >Web-Frontend >js-Tutorial >Enthüllte Abschlüsse: Erkundung der verborgenen Bereiche von JavaScript

Enthüllte Abschlüsse: Erkundung der verborgenen Bereiche von JavaScript

DDD
DDDOriginal
2024-12-12 12:22:24296Durchsuche

Closures Unveiled: Exploring the Hidden Realms of JavaScript

Inhaltsverzeichnis

  • Dem Coding-Chaos entkommen
  • Was genau ist ein Abschluss?
  • Zusammenbruch: Schließungen enthüllt
  • Praktische Zauberkunst: Eine Caching-Reise mit Abschlüssen
  • Häufige Fallstricke und wie man sie umgeht
  • Die Reise geht weiter

Dem Codierungschaos entkommen ?‍♂️

Haben Sie jemals das Gefühl gehabt, dass Ihr Code einen eigenen Kopf hat – er wird unordentlich und weigert sich, organisiert zu bleiben? Keine Sorge, das haben wir alle schon erlebt. JavaScript kann selbst für erfahrene Zauberer schwierig sein. Aber was wäre, wenn ich Ihnen sagen würde, dass es eine Geheimwaffe gibt, um die Dinge unter Kontrolle zu halten? Geben Sie Abschlüsse ein.

Stellen Sie sich einen Verschluss als einen magischen Rucksack vor, den Ihre Funktion trägt und der Variablen und Erinnerungen speichert, die sie später möglicherweise benötigt. Diese kleinen Teile der Programmiermagie halten Ihren Code organisiert, verwalten den Status ohne Unordnung und öffnen die Tür zu dynamischen, flexiblen Mustern.

Durch die Beherrschung von Abschlüssen erschließen Sie ein neues Maß an Kraft und Eleganz in Ihrem Code. Schnappen Sie sich also Ihren Programmierstab (oder einen starken Kaffee ☕) und lassen Sie uns gemeinsam in diese verborgenen Bereiche vordringen. ?✨


Was genau ist eine Schließung? ?

Ein Abschluss ist einfach eine Funktion, die sich Variablen aus ihrer ursprünglichen Umgebung merkt – auch nachdem diese Umgebung nicht mehr existiert. Anstatt diese Variablen zu verwerfen, verstaut JavaScript sie, damit sie bei Bedarf abgerufen werden können.

const createCounter = () => {
    let count = 0; // Private variable in the closure's secret realm

    return () => {
        count++; // Whispers an increment to the hidden counter
        return count; // Reveal the mystical number
    };
}

// Summoning our magical counter
const counter = createCounter();

console.log(counter()); // Outputs: 1
console.log(counter()); // Outputs: 2
console.log(counter()); // Outputs: 3
console.log(counter.count);  // Outputs: undefined (`count` is hidden!) ?️‍♀️

Die innere Funktion behält den Zugriff auf count, auch wenn die Ausführung von createCounter abgeschlossen ist. Dieser „Speicher“ ist die Essenz eines Abschlusses – er schützt Ihre Daten und ermöglicht leistungsstarken, flexiblen Code. ?✨


Aufschlüsselung: Schließungen enthüllt?

Auch wenn sich Abschlüsse magisch anfühlen, sind sie einfach das Ergebnis davon, wie JavaScript mit Umfang und Speicher umgeht. Jede Funktion trägt einen Link zu ihrer lexikalischen Umgebung – dem Kontext, in dem sie definiert wurde.

? Eine lexikalische Umgebung ist eine strukturierte Aufzeichnung von Variablenbindungen, die definiert, was in diesem Bereich zugänglich ist. Es ist wie eine Karte, die zeigt, welche Variablen und Funktionen sich in einem bestimmten Block oder einer bestimmten Funktion befinden.

Abschlüsse sind dynamische Geschichtenerzähler?

Abschlüsse binden nicht nur einen Wert; Sie verfolgen Veränderungen im Laufe der Zeit. Wenn die Variable des äußeren Bereichs aktualisiert wird, sieht der Abschluss den neuen Wert.

const createCounter = () => {
    let count = 0; // Private variable in the closure's secret realm

    return () => {
        count++; // Whispers an increment to the hidden counter
        return count; // Reveal the mystical number
    };
}

// Summoning our magical counter
const counter = createCounter();

console.log(counter()); // Outputs: 1
console.log(counter()); // Outputs: 2
console.log(counter()); // Outputs: 3
console.log(counter.count);  // Outputs: undefined (`count` is hidden!) ?️‍♀️

Warum sind Verschlüsse magische Essentials? ?

Abschlüsse ermöglichen Kapselung durch die Erstellung privater Variablen mit kontrolliertem Zugriff, Verwalten des Status über mehrere Aufrufe hinweg, ohne sich auf Globals verlassen zu müssen, und ermöglichen dynamische Verhaltensweisen wie Fabriken und Rückrufe , und Haken.

Frameworks wie React nutzen diese Kräfte und sorgen dafür, dass Funktionskomponenten zustandslos bleiben, während sie den Zustand mit Hooks wie useState verwalten – alles dank der Magie von Abschlüssen.


Praktische Zauberkunst: Eine Caching-Reise mit Verschlüssen ?‍♂️

Abschlüsse können den Zustand speichern, was sie ideal für Zaubersprüche wie das Caching der Ergebnisse teurer Vorgänge macht. Lassen Sie uns dies Schritt für Schritt erkunden und unseren Zauber nach und nach verbessern.

Schritt 1: ?️ Der Memory Keeper – Grundlegendes Caching

Unser erster Zauber ist einfach, aber wirkungsvoll: ein Erinnerungsbewahrer. Wenn Sie erneut nach denselben Eingaben gefragt werden, wird das zwischengespeicherte Ergebnis sofort zurückgegeben.

// A variable in the global magical realm
let multiplier = 2;

const createMultiplier = () => {
  // The inner function 'captures' the essence of the outer realm
  return (value: number): number => value * multiplier;
}; 


// Our magical transformation function
const double = createMultiplier();

console.log(double(5)); // Outputs: 10
multiplier = 3;
console.log(double(5)); // Outputs: 15 (The magic adapts!) ✨

Schritt 2: ⏳ Der verblassende Zauber – Ablaufender Cache

Einige Zaubersprüche sind jedoch zu mächtig, um ewig zu wirken. Erweitern wir unseren Cache um die Fähigkeit, alte Erinnerungen zu vergessen. Wir erstellen einen CacheEntry, um nicht nur Werte, sondern auch deren magische Lebensdauer zu speichern.

(Beachten Sie, wie wir auf der vorherigen Idee aufbauen – Abschlüsse machen es einfach, Komplexität hinzuzufügen, ohne den Überblick zu verlieren.)

function withCache(fn: (...args: any[]) => any) {
  const cache: Record<string, any> = {};

  return (...args: any[]) => {
    const key = JSON.stringify(args);

    // Have we encountered these arguments before?
    if (key in cache) return cache[key]; // Recall of past magic! ?

    // First encounter? Let's forge a new memory
    const result = fn(...args);
    cache[key] = result;

    return result;
  };
}

// Example usage
const expensiveCalculation = (x: number, y: number) => {
  console.log('Performing complex calculation');
  return x * y;
};

// Summoning our magical cached calculation
const cachedCalculation = withCache(expensiveCalculation);

console.log(cachedCalculation(4, 5)); // Calculates and stores the spell
console.log(cachedCalculation(4, 5)); // Uses cached spell instantly

Schritt 3: ? Async Magic – Umgang mit Versprechen

Manchmal brauchen Zauber Zeit – etwa das Warten auf die Antwort eines entfernten Orakels (oder einer API). Unser Zauber kann auch damit umgehen. Es wartet auf das Versprechen, speichert den aufgelösten Wert und gibt ihn in Zukunft zurück – keine wiederholten Abrufe.

type CacheEntry<T> = { value: T; expiry: number; };

function withCache<T extends (...args: any[]) => any>(
  fn: T,
  expirationMs: number = 5 * 60 * 1000, // Default 5 minutes
) {
  const cache = new Map<string, CacheEntry<ReturnType<T>>>();

  return (...args: Parameters<T>): ReturnType<T> => {
    const key = JSON.stringify(args);
    const now = Date.now(); // Current magical moment
    const cached = cache.get(key);

    // Is our magical memory still vibrant?
    if (cached && now < cached.expiry) return cached.value;

    // The memory has faded; it’s time to create new ones!
    const result = fn(...args);
    cache.set(key, { value: result, expiry: now + expirationMs });

    return result;
  };
}

// ...

const timeLimitedCalc = 
  withCache(expensiveCalculation, 3000); // 3-second cache

console.log(timeLimitedCalc(4, 5)); // Stores result with expiration
console.log(timeLimitedCalc(4, 5)); // Returns cached value before expiry

setTimeout(() => {
  console.log(timeLimitedCalc(4, 5)); // Recalculates after expiration
}, 3000);

Entdecken Sie hier den gesamten Zauber.

Die Herausforderung des Zauberers ??‍♂️

Unser Caching-Zauber ist mächtig, aber er ist erst der Anfang. Denken Sie, Sie können den Code verbessern? Erwägen Sie das Hinzufügen einer Fehlerbehandlung, die Implementierung einer magischen Speicherbereinigung oder die Entwicklung ausgefeilterer Caching-Strategien. Die wahre Kunst des Codierens liegt im Experimentieren, im Überschreiten von Grenzen und im Neudenken von Möglichkeiten! ??


Häufige Fallstricke und wie man ihnen ausweicht ?️

Schließungen sind mächtig, aber selbst die besten Zauber bergen Risiken. Lassen Sie uns einige häufige Fallstricke und ihre Lösungen aufdecken, damit Sie Abschlüsse souverän meistern können.

Fallstrick Nr. 1: ?️ Die Sneaky-Loop-Falle

Ein klassisches JavaScript-Problem, das oft in Coding-Interviews erwähnt wird, betrifft Schleifen – insbesondere, wie sie mit Schleifenvariablen und -abschlüssen umgehen.

// ...

// The memory has faded; it’s time to create new ones!
const result = fn(...args);

if (result instanceof Promise) {
  return result.then((value) => {
    cache.set(key, { value, expiry: now + expirationMs });
    return value;
  });
}

// ...

Im obigen Beispiel wird die Zahl 5 fünfmal protokolliert, da var eine einzige gemeinsame Variable für alle Abschlüsse erstellt.

Lösung 1: Verwenden Sie let, um den Blockumfang sicherzustellen.
Das Schlüsselwort let erstellt für jede Iteration eine neue Variable mit Blockbereich, sodass Abschlüsse den richtigen Wert erfassen.

const createCounter = () => {
    let count = 0; // Private variable in the closure's secret realm

    return () => {
        count++; // Whispers an increment to the hidden counter
        return count; // Reveal the mystical number
    };
}

// Summoning our magical counter
const counter = createCounter();

console.log(counter()); // Outputs: 1
console.log(counter()); // Outputs: 2
console.log(counter()); // Outputs: 3
console.log(counter.count);  // Outputs: undefined (`count` is hidden!) ?️‍♀️

Lösung 2: Verwenden Sie einen IIFE (Immediately Invoked Function Expression).
Ein IIFE erstellt für jede Iteration einen neuen Bereich und stellt so die ordnungsgemäße Variablenbehandlung innerhalb der Schleife sicher.

// A variable in the global magical realm
let multiplier = 2;

const createMultiplier = () => {
  // The inner function 'captures' the essence of the outer realm
  return (value: number): number => value * multiplier;
}; 


// Our magical transformation function
const double = createMultiplier();

console.log(double(5)); // Outputs: 10
multiplier = 3;
console.log(double(5)); // Outputs: 15 (The magic adapts!) ✨

Bonus-Tipp: ? Der funktionale Trick.
Nur wenige Zauberer kennen diesen Zauber, und um ehrlich zu sein, habe ich ihn in Programmierinterviews selten (wenn überhaupt) erwähnt. Wussten Sie, dass setTimeout zusätzliche Argumente direkt an seinen Rückruf übergeben kann?

function withCache(fn: (...args: any[]) => any) {
  const cache: Record<string, any> = {};

  return (...args: any[]) => {
    const key = JSON.stringify(args);

    // Have we encountered these arguments before?
    if (key in cache) return cache[key]; // Recall of past magic! ?

    // First encounter? Let's forge a new memory
    const result = fn(...args);
    cache[key] = result;

    return result;
  };
}

// Example usage
const expensiveCalculation = (x: number, y: number) => {
  console.log('Performing complex calculation');
  return x * y;
};

// Summoning our magical cached calculation
const cachedCalculation = withCache(expensiveCalculation);

console.log(cachedCalculation(4, 5)); // Calculates and stores the spell
console.log(cachedCalculation(4, 5)); // Uses cached spell instantly

Fallstrick Nr. 2: ? Speicherlecks – stille Bedrohung

Abschlüsse behalten einen Verweis auf ihren äußeren Bereich bei, was bedeutet, dass Variablen möglicherweise länger als erwartet verbleiben, was zu Speicherverlusten führt.

type CacheEntry<T> = { value: T; expiry: number; };

function withCache<T extends (...args: any[]) => any>(
  fn: T,
  expirationMs: number = 5 * 60 * 1000, // Default 5 minutes
) {
  const cache = new Map<string, CacheEntry<ReturnType<T>>>();

  return (...args: Parameters<T>): ReturnType<T> => {
    const key = JSON.stringify(args);
    const now = Date.now(); // Current magical moment
    const cached = cache.get(key);

    // Is our magical memory still vibrant?
    if (cached && now < cached.expiry) return cached.value;

    // The memory has faded; it’s time to create new ones!
    const result = fn(...args);
    cache.set(key, { value: result, expiry: now + expirationMs });

    return result;
  };
}

// ...

const timeLimitedCalc = 
  withCache(expensiveCalculation, 3000); // 3-second cache

console.log(timeLimitedCalc(4, 5)); // Stores result with expiration
console.log(timeLimitedCalc(4, 5)); // Returns cached value before expiry

setTimeout(() => {
  console.log(timeLimitedCalc(4, 5)); // Recalculates after expiration
}, 3000);

Was passiert hier? Der Abschluss behält die gesamte Datenvariable bei, auch wenn nur ein kleiner Teil benötigt wird, wodurch möglicherweise erhebliche Ressourcen verschwendet werden.

Die Lösung besteht darin, sorgfältig zu verwalten, welche Schließungen unnötige Referenzen erfassen und explizit freigeben. Dadurch wird sichergestellt, dass große Datensätze nur bei Bedarf geladen und proaktiv mit einer Bereinigungsmethode freigegeben werden.

// ...

// The memory has faded; it’s time to create new ones!
const result = fn(...args);

if (result instanceof Promise) {
  return result.then((value) => {
    cache.set(key, { value, expiry: now + expirationMs });
    return value;
  });
}

// ...

Fallstrick Nr. 3: ?️ Das Mutationschaos

Schließungen können zu unerwartetem Verhalten führen, wenn der gemeinsame Status mutiert wird. Was wie eine einfache Referenz erscheint, kann zu unbeabsichtigten Nebenwirkungen führen.

for (var i = 0; i < 5; i++) {
  setTimeout(() => {
    console.log(i); // Logs 5, five times ?
  }, i * 1000); 
}

Was passiert hier? Die getUsers-Methode macht das Benutzerarray verfügbar, bricht die Kapselung und riskiert unbeabsichtigte Nebenwirkungen durch externe Änderungen.

Die Lösung besteht darin, eine Kopie des internen Status zurückzugeben. Dadurch werden externe Änderungen verhindert, die Datenintegrität gewahrt und die interne Logik des Verschlusses geschützt.

for (let i = 0; i < 5; i++) {
  setTimeout(() => {
    console.log(i); // Works as expected ?
  }, i * 1000);
}

Die goldenen Regeln der Abschlussbeherrschung?

  1. Seien Sie bei Erfassungen bewusst: Verstehen Sie, welche Abschlüsse erfasst werden, um unnötige Abhängigkeiten und Speicherprobleme zu vermeiden.
  2. Variablen mit Bedacht eingrenzen: Verwenden Sie Block-Scoping, um gemeinsame Referenzfehler zu verhindern und eine korrekte Variablenerfassung sicherzustellen.
  3. Umfassen Sie die Unveränderlichkeit: Bevorzugen Sie unveränderliche Muster und geben Sie Kopien zurück, anstatt den gemeinsamen Zustand zu ändern, um Nebenwirkungen zu vermeiden.
  4. Üben Sie die Bereinigung: Geben Sie nicht benötigte Referenzen frei, um Speicherlecks zu verhindern, insbesondere bei großen oder sensiblen Daten.

Wenn Sie diese Techniken beherrschen, können Sie die Magie des Verschlusses selbstbewusst nutzen. Wahre Meisterschaft liegt im Verstehen, nicht im Vermeiden. ✨


Die Reise geht weiter

Abschlüsse mögen zunächst komplex erscheinen, aber sie eröffnen das Potenzial, eleganteren und effizienteren Code zu schreiben. Durch die Umwandlung einfacher Funktionen in persistente, zustandsbehaftete Einheiten können Abschlüsse Geheimnisse auf elegante Weise über Zeit und Raum hinweg teilen. Diese leistungsstarke Funktion macht JavaScript von einer einfachen Skriptsprache zu einem leistungsstarken und flexiblen Werkzeug zur Lösung komplexer Probleme.

Ihre Reise endet hier nicht; Tauchen Sie tiefer in asynchrone Muster, funktionale Programmierung und das Innenleben von JavaScript-Engines ein. Jeder Schritt enthüllt weitere Schichten dieser bezaubernden Sprache und bringt neue Ideen und Lösungen hervor.

Wahre Meisterschaft entsteht schließlich durch Neugier und Erkundung. Möge Ihr Code immer elegant, effizient und ein bisschen magisch sein. ?

Das obige ist der detaillierte Inhalt vonEnthüllte Abschlüsse: Erkundung der verborgenen Bereiche von JavaScript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn