【03问:闭包的理解与应用】

前言

闭包是 JavaScript 中一个非常强大的概念,它不仅在日常开发中十分常见,而且是许多高级编程技巧和设计模式的基础。本文将深入探讨闭包的定义、原理、常见应用场景以及一些实际例子,帮助你更好地理解和运用闭包。

一、什么是闭包

闭包是指函数在创建时,保存了其在词法作用域中的变量的引用。换句话说,闭包允许函数在其外部函数的作用域之外访问该作用域内的变量。

简单的闭包示例如下:

function outerFunction() {
    let outerVariable = 'I am outside!';

    function innerFunction() {
        console.log(outerVariable);
    }

    return innerFunction;
}

const myClosure = outerFunction();
myClosure(); // 输出: I am outside!

在这个例子中,innerFunction 是一个闭包,因为它可以访问 outerFunction 中的 outerVariable,即使 outerFunction 已经执行完毕并从调用栈中移除了。

简单来说就是一个函数内部返回另一个函数,且内部函数操作(访问、赋值)着 外部函数的变量,形成这个条件就是闭包。

二、闭包的原理

要理解闭包的工作原理,需要了解 JavaScript 的执行上下文和作用域链。当一个函数被创建时,它会保存一个对其词法作用域的引用,这个引用称为闭包。在函数执行过程中,作用域链决定了变量的查找顺序。当函数访问一个变量时,JavaScript 引擎会首先在当前作用域中查找该变量,如果找不到,则沿着作用域链向上查找,直到找到该变量或到达全局作用域。

三、闭包的应用场景

1.数据封装和隐藏

闭包可以用于创建私有变量和方法,从而实现数据的封装和隐藏。

function createCounter() {
    let count = 0;

    return {
        increment: function() {
            count++;
            return count;
        },
        decrement: function() {
            count--;
            return count;
        },
        getCount: function() {
            return count;
        }
    };
}

const counter = createCounter();
console.log(counter.increment()); // 输出: 1
console.log(counter.decrement()); // 输出: 0
console.log(counter.getCount());  // 输出: 0

在这个例子中,count 变量被封装在 createCounter 函数内部,通过返回的对象方法可以访问和修改 count,但外部代码无法直接访问 count

2.函数工厂

闭包可以用于创建具有特定环境的函数。

function createGreeting(greeting) {
    return function(name) {
        console.log(`${greeting}, ${name}!`);
    };
}

const sayHello = createGreeting('Hello');
const sayHi = createGreeting('Hi');

sayHello('Alice'); // 输出: Hello, Alice!
sayHi('Bob');      // 输出: Hi, Bob!

在这个例子中,createGreeting 返回的每个函数都保留了 greeting 参数的值,从而形成了不同的闭包。

3.防抖和节流

闭包常用于防抖(debounce)和节流(throttle)函数中,以避免某些函数被频繁调用。

// func是用户传入需要防抖的函数
// wait是等待时间
const debounce = (func, wait = 50) => {
  // 缓存一个定时器id
  let timer = 0
  // 这里返回的函数是每次用户实际调用的防抖函数
  // 如果已经设定过定时器了就清空上一次的定时器
  // 开始一个新的定时器,延迟执行用户传入的方法
  return function(...args) {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      func.apply(this, args)
    }, wait)
  }
}


btn.onclick = debounce(() => {
  console.log('点了');
}, 1000)
function throttle(fn,delay){
  var starttime=0;
  return function f() {
      var nowtime=Date.now();
      if (nowtime-starttime>delay){
          fn.call(document);
          // fn.call(this);


          // fn();
          starttime=nowtime;
      }
  }
}
document.onmousemove=throttle(function () {
      console.log(Math.random());
  console.log(this);
},1000);

四、闭包的注意事项

1.内存泄漏

由于闭包持有对其外部作用域变量的引用,可能导致内存泄漏。在不再需要闭包时,确保移除对闭包的引用,以便垃圾回收机制能够回收内存。

2.性能

虽然闭包非常强大,但过多使用闭包可能会导致性能问题,特别是在需要大量创建和销毁闭包的场景中。

总结

闭包是 JavaScript 中一个重要且强大的概念,它使得函数可以访问其词法作用域中的变量,并在许多编程场景中提供了强大的能力。理解闭包的工作原理和应用场景,可以帮助你编写更健壮和灵活的代码。在实际开发中,合理使用闭包可以提升代码的可读性和维护性,同时避免潜在的性能问题和内存泄漏。

  • 16
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值