1. 程式人生 > 其它 >個人閉包理解(結合程式碼)

個人閉包理解(結合程式碼)

使用debounce函式做了一個閉包的個人理解<!DOCTYPE html>

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>function debounce</title>
</head>
<body>
  <button class="btn">點選按鈕</button>
  <div>
    <p>測試防抖效果:</p>
    <p class="text"></p>
  </div>
  <script>
    function
debounce(fn, delay) { let timeId; return function() { if (timeId) clearTimeout(timeId); timeId = setTimeout(fn, delay); } } /* 包含上下文:又稱 包含作用域: 當前函式所在的上下文(作用域)為其包含上下文(包含作用域) */ /* 包含上下文變數物件 又稱 包含作用域變數物件: 函式執行時會先建立其包含(上下文/作用域)變數物件:其初始屬性和值為arguments,其他變數或者函式在預編譯階段新增,var會將變數直接初始化,let和const則只對變數進行宣告,在程式碼執行過程中呼叫只宣告未初始化的變數名稱會報錯
*/ /* 利用閉包實現;閉包思路理解: 當debounce函式呼叫時,返回了一個函式,即clickFun,後debounce上下文(作用域)在執行棧中銷燬,clickFun保留了其包含上下文變數物件(可自己理解名稱為debounce的一個物件)。其timeId的值為undefined(可理解為debounce.timeId = undefined);當執行clickFun函式時,會給timeId賦值setTimeout(fn, delay),(理解為debounce.timeId = setTimeout(fn, delay)),即再次呼叫函式clickFun會有一個timeId = setTimeout(fn, delay)的timeId初始值,而因為debounce函式沒有呼叫,所以debounce中的timeId值不會重新初始化為undefined
*/
const clickFun = debounce(() => { text.innerHTML='點選按鈕之後1秒內不點選按鈕則觸發防抖事件'; }, 1000); console.log(clickFun); /* 列印值為 ƒ () { if (timeId) clearTimeout(timeId); timeId = setTimeout(fn, delay); } */ const btn = document.querySelector('.btn'); const text = document.querySelector('.text'); btn.addEventListener('click', clickFun); </script> </body> </html>




// 閉包存在的作用:timeId定義為了debounce區域性變數中,沒有定義到全域性中,防止了變數名稱汙染全域性作用域。同時,使用閉包函式延伸了timeId的作用範圍,使外部作用域可以在不重複呼叫debounce函式的情況下對timeId進行使用。
// 使用閉包的話會在記憶體中儲存其相關的包含作用域變數物件,大量使用閉包會造成記憶體洩漏。
// 可優化點:在確定不再使用閉包函式的情況下可以將儲存閉包函式的變數值賦值為null
// 程式碼中
clickFun變數僅為理解閉包執行定義,可以不定義此變數,直接在addEventListener中呼叫debounce(()=>{}, 1000)的方式呼叫閉包函式