Rumah  >  Artikel  >  hujung hadapan web  >  Pengenalan ringkas kepada penutupan JavaScript

Pengenalan ringkas kepada penutupan JavaScript

WBOY
WBOYke hadapan
2023-01-21 06:30:021106semak imbas

Artikel ini membawakan anda pengetahuan yang berkaitan tentang JavaScript, yang terutamanya memperkenalkan isu yang berkaitan dengan penutupan JavaScript Terdapat banyak versi konsep penutupan, dan tempat yang berbeza mempunyai pendapat yang berbeza tentang penutupan. Mari kita lihat membantu semua orang.

Pengenalan ringkas kepada penutupan JavaScript

Apakah itu penutupan?

Konsep penutupan mempunyai banyak versi, dan tempat yang berbeza mempunyai pendapat yang berbeza tentang penutupan

Wikipedia: Dalam sains komputer, penutupan (Bahasa Inggeris: Closure), Juga dikenali sebagai Lexical Closure atau penutupan fungsi, ia adalah teknik untuk melaksanakan pengikatan leksikal dalam bahasa pengaturcaraan yang menyokong fungsi kelas pertama.

MDN: Penutupan (penutupan) ialah fungsi dan keadaan persekitaran sekelilingnya yang digabungkan (persekitaran leksikal , persekitaran leksikal ).

Pemahaman peribadi:

  • Penutupan ialah fungsi (mengembalikan fungsi)
  • Fungsi yang dikembalikan menyimpan rujukan kepada pembolehubah luaran

Contoh mudah

function fn() {    let num = 1;    return function (n) {        return n + num
    }
}let rFn = fn()let newN = rFn(3) // 4

Skop pembolehubah num berada dalam fungsi fn, tetapi fungsi rFn boleh mengakses pembolehubah num Ini bermakna fungsi penutupan boleh mengakses pembolehubah fungsi luaran.

Lihat penutupan daripada penyahpepijatan penyemak imbas dan penyahpepijatan VSCode Nodejs

  • Pelayar

Pengenalan ringkas kepada penutupan JavaScript

  • Kod VS bekerjasama dengan Node.js

Pengenalan ringkas kepada penutupan JavaScript

untuk melihat bahawa fn dalam Closure ialah fungsi penutupan, yang menyimpan pembolehubah num.

Penutupan klasik: mekanisme acara berbenang tunggal + masalah gelung dan penyelesaian

for (var i = 1; i  {    console.log(i);
  }, i * 1000);
}

Hasil keluaran semuanya 6, kenapa?

  • untuk gelung ialah tugas segerak
  • tugas tak segerak setTimeout

untuk gelung sekali, tugas tak segerak setTimeout akan ditambahkan pada baris gilir tugas tak segerak penyemak imbas Selepas tugas segerak selesai, tugas baharu diambil daripada tugas tak segerak dan dilaksanakan dalam utas. Memandangkan setTimeout boleh mengakses pembolehubah luaran i, apabila tugas penyegerakan selesai, i telah menjadi 6, dan pembolehubah i yang boleh diakses dalam setTimeout adalah kesemuanya 6.

Penyelesaian 1: Gunakan pernyataan let

for (var i = 1; i  {    console.log(i);
  }, i * 1000);
}

Penyelesaian 2: Fungsi laksana sendiri + penutupan

for (var i = 1; i  {    console.log(i);
  }, i * 1000)
  })(i)
}

Penyelesaian 3: setTimeout melepasi parameter ketiga

Parameter ketiga bermaksud: parameter tambahan, apabila pemasa tamat tempoh, ia akan dihantar sebagai parameter kepada fungsi yang akan dilaksanakan

for (var i = 1; i  {    console.log(j);
  }, 1000 * i, i);
}

Penutupan dan fungsi Currying

function add(num) {  return function (y) {    return num + y;
  };
};let incOneFn = add(1); let n = incOneFn(1);  // 2let decOneFn = add(-1); let m = decOneFn(1); // 0

参数 fungsi tambah menyimpan pembolehubah fungsi penutupan.

Kesan sebenar

Penutupan memainkan peranan yang sangat penting dalam pengaturcaraan berfungsi awal seperti lodash digunakan untuk mengimbangi kekurangan JavaScript, dan terdapat sejumlah besar senario penggunaan. untuk penutupan.

Senario penggunaan

  • Buat pembolehubah persendirian
  • Lanjutkan kitaran hayat pembolehubah

Fungsi Pendikit

menghalang kelakuan menatal dan pelaksanaan fungsi yang berlebihan Ia mesti dikurangkan Fungsi pendikit menerima 函数 + 时间 sebagai parameter, yang merupakan pembolehubah dalam penutupan versi setTimeout :

function throttle(fn, time=300){    var t = null;    return function(){        if(t) return;
        t = setTimeout(() => {
            fn.call(this);
            t = null;
        }, time);
    }
}

Fungsi anti goncang

Perlaksanaan mudah fungsi anti goncang berdasarkan setTimeout

function debounce(fn,wait){    var timer = null;    return function(){        if(timer !== null){            clearTimeout(timer);
        }
        timer = setTimeout(fn,wait);
    }
}

React. useCallback closure Masalah perangkap

Perihalan masalah: 父/子 Perhubungan komponen, komponen ibu bapa dan anak boleh menggunakan acara klik untuk mengubah suai data keadaan pada masa yang sama dan komponen anak mendapat atribut acara prop yang diluluskan, iaitu useCallback dioptimumkan. Iaitu, fungsi yang dioptimumkan ini mempunyai perangkap penutupan, (nilai keadaan awal sentiasa disimpan)

import { useState, useCallback, memo } from "react";const ChildWithMemo = memo((props: any) => {  return (    <div>
      <button>Child click</button>
    </div>
  );
});const Parent = () => {  const [count, setCount] = useState(1);  const handleClickWithUseCallback = useCallback(() => {    console.log(count);
  }, []); // 注意这里是不能监听 count, 因为每次变化都会重新绑定,造成造成子组件重新渲染

  return (    <div>
      <div>parent count : {count}</div>
      <button> setCount(count + 1)}>click</button>
      <childwithmemo></childwithmemo>
    </div>
  );
};export default Parent
  • ChildWithMemo menggunakan memo untuk pengoptimuman dan
  • handleClickWithUseCallback menggunakan useCallback untuk pengoptimuman

Masalahnya ialah apabila subkomponen diklik, kiraan output ialah nilai awal (ditutup).

Penyelesaiannya ialah menggunakan useRef untuk menyimpan fungsi pembolehubah operasi:

import { useState, useCallback, memo, useRef } from "react";const ChildWithMemo = memo((props: any) => {  console.log("rendered children")  return (    <div>
      <button> props.countRef.current()}>Child click</button>
    </div>
  );
});const Parent = () => {  const [count, setCount] = useState(1);  const countRef = useRef<any>(null)

  countRef.current = () => {    console.log(count);
  }  return (    <div>
      <div>parent count : {count}</div>
      <button> setCount(count + 1)}>click</button>
      <childwithmemo></childwithmemo>
    </div>
  );
};export default Parent</any>

Sebagai tindak balas kepada masalah ini, React setelah meluluskan cadangan komuniti untuk menambah useEvent, tetapi kemudiannya Isu semantik useEvent telah ditinggalkan Sekarang, untuk pengoptimuman pemaparan, React menggunakan penyelesaian pengoptimuman kompilasi. Malah, masalah yang sama juga akan berlaku dalam useEffect Beri perhatian kepada perangkap penutupan apabila menggunakannya.

Isu prestasi

  • Jangan tentukan penutupan sewenang-wenangnya Setelah ditentukan, anda mesti mencari lokasi yang sesuai untuk pemusnahan. Oleh kerana pembolehubah penutupan disimpan dalam ingatan dan tidak akan dimusnahkan, ia menduduki jumlah memori yang tinggi.

Gunakan garis masa fungsi panel krom + panel profil

  1. Buka alatan pembangun dan pilih panel Garis Masa
  2. di bahagian atas Capture medan Semak Memori
  3. dan klik butang rekod di penjuru kiri sebelah atas.
  4. Lakukan pelbagai operasi pada halaman untuk mensimulasikan penggunaan pengguna.
  5. Selepas tempoh masa, klik butang berhenti dalam kotak dialog, dan penggunaan memori dalam tempoh ini akan dipaparkan pada panel.

[Cadangan berkaitan: Tutorial video JavaScript, bahagian hadapan web]

Atas ialah kandungan terperinci Pengenalan ringkas kepada penutupan JavaScript. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:juejin.im. Jika ada pelanggaran, sila hubungi admin@php.cn Padam