Rumah > hujung hadapan web > tutorial js > Penutupan Didedahkan: Meneroka Alam Tersembunyi JavaScript

Penutupan Didedahkan: Meneroka Alam Tersembunyi JavaScript

DDD
Lepaskan: 2024-12-12 12:22:24
asal
291 orang telah melayarinya

Closures Unveiled: Exploring the Hidden Realms of JavaScript

Jadual Kandungan

  • Melarikan diri dari Kekacauan Pengekodan
  • Apakah Sebenarnya Penutupan?
  • Memecahkan: Penutupan Didedahkan
  • Spellcraft Praktikal: Perjalanan Caching dengan Penutupan
  • Perangkap Biasa dan Cara Mengelaknya
  • Perjalanan Berterusan

Melarikan diri dari Kekacauan Pengekodan ?‍♂️

Pernah merasakan kod anda mempunyai fikirannya sendiri—berkecoh dan enggan kekal teratur? Jangan risau, kita semua pernah ke sana. JavaScript boleh menjadi rumit, walaupun untuk ahli sihir berpengalaman. Tetapi bagaimana jika saya memberitahu anda ada senjata rahsia untuk mengawal keadaan? Masukkan penutupan.

Fikirkan penutupan sebagai beg galas ajaib fungsi anda membawa, menyimpan pembolehubah dan kenangan yang mungkin diperlukan kemudian. Keajaiban pengaturcaraan kecil ini memastikan kod anda teratur, mengurus keadaan tanpa kekacauan dan membuka pintu kepada corak yang dinamik dan fleksibel.

Dengan menguasai penutupan, anda akan membuka kunci tahap kuasa dan keanggunan baharu dalam kod anda. Jadi, ambil tongkat pengekodan anda (atau kopi pekat ☕), dan mari kita menerokai alam tersembunyi ini bersama-sama. ?✨


Apakah Sebenarnya Penutupan? ?

Penutupan hanyalah fungsi yang mengingati pembolehubah daripada persekitaran asalnya—walaupun selepas persekitaran itu tidak lagi wujud. Daripada membuang pembolehubah tersebut, JavaScript menyimpannya, bersedia untuk dipanggil apabila diperlukan.

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!) ?️‍♀️
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Fungsi dalaman mengekalkan akses untuk mengira, walaupun createCounter telah selesai dijalankan. "Memori" ini ialah intipati penutupan—memastikan data anda selamat dan membolehkan kod yang berkuasa dan fleksibel. ?✨


Pecah: Penutupan Didedahkan ?

Walaupun penutupan mungkin terasa ajaib, ia hanyalah hasil daripada cara JavaScript mengendalikan skop dan ingatan. Setiap fungsi membawa pautan ke persekitaran leksikalnya—konteks di mana ia ditakrifkan.

? Persekitaran leksikal ialah rekod berstruktur bagi pengikatan pembolehubah, mentakrifkan perkara yang boleh diakses dalam skop itu. Ia seperti peta yang menunjukkan pembolehubah dan fungsi yang tinggal di dalam blok atau fungsi tertentu.

Penutup Adakah Pencerita Dinamik?

Penutupan tidak hanya mengunci satu nilai; mereka menjejaki perubahan dari semasa ke semasa. Jika pembolehubah skop luar dikemas kini, penutupan melihat nilai baharu.

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!) ?️‍♀️
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Mengapa Penutupan Adalah Penting Ajaib? ?

Penutupan membolehkan pengkapsulan dengan mencipta pembolehubah peribadi dengan akses terkawal, urus keadaan merentas berbilang panggilan tanpa bergantung pada global dan kuasa tingkah laku dinamik seperti kilang, panggilan balik , dan cangkuk.

Rangka kerja seperti React memanfaatkan kuasa ini, membiarkan komponen berfungsi kekal tanpa kewarganegaraan sambil menguruskan keadaan dengan cangkuk seperti useState—semuanya berkat keajaiban penutupan.


Spellcraft Praktikal: Perjalanan Caching dengan Penutupan ?‍♂️

Penutupan boleh menyimpan keadaan, menjadikannya sesuai untuk ejaan seperti caching hasil operasi yang mahal. Mari kita terokai langkah demi langkah ini dan tingkatkan mantera kita semasa kita pergi.

Langkah 1: ?️ Penyimpan Memori – Caching Asas

Mantra pertama kami adalah ringkas tetapi berkuasa: penjaga ingatan. Jika diminta untuk input yang sama sekali lagi, ia mengembalikan hasil cache serta-merta.

// 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!) ✨
Salin selepas log masuk
Salin selepas log masuk

Langkah 2: ⏳ Ejaan Pudar – Cache Tamat Tempoh

Sesetengah mantera, walau bagaimanapun, terlalu kuat untuk kekal selama-lamanya. Mari tingkatkan cache kita dengan keupayaan untuk melupakan kenangan lama. Kami akan mencipta CacheEntry untuk menyimpan bukan sahaja nilai, tetapi jangka hayatnya yang ajaib.

(Perhatikan cara kami membina idea sebelumnya—penutupan memudahkan untuk menambah kerumitan tanpa kehilangan landasan.)

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
Salin selepas log masuk
Salin selepas log masuk

Langkah 3: ? Async Magic – Pengendalian Janji

Kadangkala, mantra memerlukan masa—seperti menunggu oracle (atau API) yang jauh untuk bertindak balas. Mantra kami juga boleh mengatasinya. Ia akan menunggu janji, menyimpan nilai yang diselesaikan dan mengembalikannya pada masa hadapan—tiada pengambilan berulang.

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);
Salin selepas log masuk
Salin selepas log masuk

Teroka ejaan penuh di sini.

Cabaran Ahli Sihir ??‍♂️

Mantra caching kami hebat, tetapi ia hanya permulaan. Fikirkan anda boleh tingkatkan kod? Pertimbangkan untuk menambah pengendalian ralat, melaksanakan pembersihan memori ajaib atau mencipta strategi caching yang lebih canggih. Seni pengekodan sebenar terletak pada percubaan, menolak sempadan, dan membayangkan semula kemungkinan! ??


Perangkap Biasa dan Bagaimana Mengelaknya ?️

Penutupan adalah hebat, tetapi mantra terbaik pun datang dengan risiko. Mari kita temukan beberapa perangkap biasa dan penyelesaiannya untuk membantu anda menggunakan penutupan dengan yakin.

Perangkap #1: ?️ Perangkap Gelung Sneaky

Gotch JavaScript klasik, sering dipaparkan dalam temu bual pengekodan, melibatkan gelung—khususnya, cara mereka mengendalikan pembolehubah gelung dan penutupan.

// ...

// 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;
  });
}

// ...
Salin selepas log masuk
Salin selepas log masuk

Contoh di atas mencatatkan nombor 5 lima kali kerana var mencipta pembolehubah tunggal yang dikongsi untuk semua penutupan.

Penyelesaian 1: Gunakan let untuk memastikan skop blok.
Kata kunci let mencipta pembolehubah berskop blok baharu untuk setiap lelaran, jadi penutupan menangkap nilai yang betul.

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!) ?️‍♀️
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Penyelesaian 2: Gunakan IIFE (Ungkapan Fungsi Dipanggil Serta-merta).
IIFE mencipta skop baharu untuk setiap lelaran, memastikan pengendalian pembolehubah yang betul dalam gelung.

// 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!) ✨
Salin selepas log masuk
Salin selepas log masuk

Petua Bonus: ? Helah Fungsional.
Beberapa ahli sihir mengetahui mantra ini, dan sejujurnya, saya jarang (jika pernah) melihatnya disebut semasa temu bual pengekodan. Tahukah anda bahawa setTimeout boleh menghantar argumen tambahan terus kepada panggilan baliknya?

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
Salin selepas log masuk
Salin selepas log masuk

Perangkap #2: ? Kebocoran Memori – Ancaman Senyap

Penutupan mengekalkan rujukan kepada skop luarnya, yang bermaksud pembolehubah mungkin kekal lebih lama daripada yang dijangkakan, yang membawa kepada kebocoran memori.

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);
Salin selepas log masuk
Salin selepas log masuk

Apa yang berlaku di sini? Penutupan ini mengekalkan keseluruhan pembolehubah data, walaupun hanya sekeping kecil diperlukan, yang berpotensi membazirkan sumber yang ketara.

Penyelesaiannya adalah untuk mengurus dengan teliti perkara yang ditangkap oleh penutupan dan secara eksplisit mengeluarkan rujukan yang tidak perlu. Ini memastikan set data yang besar dimuatkan hanya apabila diperlukan dan dibebaskan secara proaktif dengan kaedah pembersihan.

// ...

// 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;
  });
}

// ...
Salin selepas log masuk
Salin selepas log masuk

Perangkap #3: ?️ Keganasan Mutasi

Penutupan boleh menyebabkan tingkah laku yang tidak dijangka apabila keadaan kongsi diubah. Perkara yang kelihatan seperti rujukan mudah boleh membawa kepada kesan sampingan yang tidak diingini.

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

Apa yang berlaku di sini? Kaedah getUsers mendedahkan tatasusunan pengguna, memecahkan enkapsulasi dan mempertaruhkan kesan sampingan yang tidak diingini daripada pengubahsuaian luaran.

Penyelesaian adalah dengan mengembalikan salinan keadaan dalaman. Ini menghalang pengubahsuaian luaran, mengekalkan integriti data dan melindungi logik dalaman penutupan.

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

Peraturan Emas Penguasaan Penutupan ?

  1. Bersungguh-sungguh Mengenai Tangkapan: Fahami perkara yang ditangkap oleh penutupan untuk mengelakkan kebergantungan dan masalah ingatan yang tidak perlu.
  2. Pembolehubah Skop Dengan Bijak: Gunakan skop blok untuk mengelakkan pepijat rujukan dikongsi dan memastikan penangkapan pembolehubah yang betul.
  3. Ambil Ketidakbolehubah: Pilih corak tidak berubah, kembalikan salinan dan bukannya mengubah keadaan kongsi, untuk mengelakkan kesan sampingan.
  4. Amalan Pembersihan: Keluarkan rujukan yang tidak diperlukan untuk mengelakkan kebocoran memori, terutamanya dengan data yang besar atau sensitif.

Menguasai teknik ini akan membantu anda menggunakan keajaiban penutupan dengan yakin. Penguasaan sejati terletak pada pemahaman, bukan penghindaran. ✨


Perjalanan Diteruskan

Penutupan mungkin pada mulanya kelihatan rumit, tetapi ia membuka kunci potensi untuk menulis kod yang lebih elegan dan cekap. Dengan menukar fungsi mudah kepada entiti yang berterusan dan berstatus, penutupan boleh berkongsi rahsia secara elegan merentas masa dan ruang. Ciri berkuasa ini meningkatkan JavaScript daripada menjadi bahasa skrip yang mudah kepada alat yang berkuasa dan fleksibel untuk menyelesaikan masalah yang rumit.

Perjalanan anda tidak berakhir di sini; menyelam lebih dalam ke dalam corak async, pengaturcaraan berfungsi dan kerja dalaman enjin JavaScript. Setiap langkah mendedahkan lebih banyak lapisan bahasa yang mempesonakan ini, mencetuskan idea dan penyelesaian baharu.

Lagipun, penguasaan sebenar datang daripada rasa ingin tahu dan penerokaan. Semoga kod anda sentiasa elegan, cekap dan agak ajaib. ?

Atas ialah kandungan terperinci Penutupan Didedahkan: Meneroka Alam Tersembunyi JavaScript. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan