前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >前端开发中真的没用到闭包嘛?九个日常案例了解常用闭包

前端开发中真的没用到闭包嘛?九个日常案例了解常用闭包

作者头像
肥晨
发布于 2025-02-27 06:20:31
发布于 2025-02-27 06:20:31
9700
代码可运行
举报
文章被收录于专栏:农民工前端农民工前端
运行总次数:0
代码可运行

导文

很多前端都感觉自己没用过闭包,当面试官问到:

“现实开发中哪里会用到闭包”

直接哑语。

我们真的没用到闭包嘛?

闭包是什么?

闭包(Closure) 是 JavaScript 中一个非常重要的概念,它涉及到函数、作用域以及变量的生命周期。简单来说,闭包是一个函数,它能够记住并访问定义时的作用域,即使这个函数在外部作用域执行时,仍然能够访问到原本定义时的局部变量。

闭包的定义

闭包的形成条件是:函数内部引用了外部函数的变量,并且这个函数在外部被调用时依然能够访问这些外部变量。换句话说,闭包是一个 “函数 + 词法作用域” 的组合。

闭包的基本特性

  1. 访问外部变量:闭包允许内部函数访问外部函数的局部变量。
  2. 变量的持久性:即使外部函数已经执行完毕,闭包中的内部函数仍然可以访问外部函数中的变量。

举个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function outer() {
  let counter = 0;

  // 内部函数
  function inner() {
    counter++;
    console.log(counter);
  }

  return inner;
}

const myClosure = outer(); // 返回了一个闭包
myClosure(); // 输出: 1
myClosure(); // 输出: 2
解释:
  • outer 是外部函数,它定义了一个局部变量 counter,并返回了内部函数 inner
  • inner 是一个闭包,它引用了外部函数 outer 中的 counter 变量。
  • 即使外部函数 outer 执行完毕,闭包 inner 仍然能够访问到 counter 变量,保持 counter 的状态。

闭包的注意事项:

  • 内存泄漏:闭包能够访问外部函数的局部变量,但如果闭包持有的变量过多且没有释放,可能导致内存泄漏。为了避免这种情况,应注意管理闭包的生命周期。
  • 变量的共享问题:如果在多个闭包中共享变量,可能会产生预期之外的行为,因此要小心作用域链的使用。

总之,闭包是 JavaScript 中非常强大和灵活的特性,它通过保持对外部变量的引用,使得函数的行为更加灵活和强大。

日常开发中哪些是用到闭包了呢?

在日常开发中,闭包的应用非常广泛,下面列举一些常见的场景。

1. 定时器和延迟执行

setTimeoutsetInterval 中,常常使用闭包来记住当前的变量或状态,进行延迟操作。

例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function countdown(seconds) {
  let timeLeft = seconds;
  const timer = setInterval(function() {
    console.log(timeLeft);
    timeLeft--;
    if (timeLeft <= 0) {
      clearInterval(timer);
      console.log("Time's up!");
    }
  }, 1000);
}

countdown(5);

这里,setInterval 中的回调函数是一个闭包,它访问了外部函数 countdown 中的 timeLeft 变量。

2. 防抖和节流(Debouncing & Throttling)

在处理大量的事件(如 scrollresizekeypress)时,常使用闭包来实现防抖(Debounce)和节流(Throttle),从而避免频繁执行。

防抖示例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function debounce(func, delay) {
  let timeout;
  return function() {
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      func.apply(this, arguments);
    }, delay);
  };
}

const log = debounce(() => console.log('Function executed!'), 1000);

window.addEventListener('resize', log);

这里,debounce 函数返回一个闭包,确保在用户停止触发事件后的延迟时间内才会执行实际的回调函数。

3. 回调函数与异步编程

在使用回调函数的异步编程中,闭包可以保持对外部变量的访问,确保异步操作完成时,能正确访问这些变量。

例如,异步请求中的闭包使用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function fetchData(url) {
  let dataLoaded = false;
  // 假设 fetch 请求完成后会调用回调函数
  fetch(url)
    .then(response => response.json())
    .then(data => {
      dataLoaded = true;
      console.log('Data fetched:', data);
    });

  return function() {
    if (dataLoaded) {
      console.log('Data has been loaded');
    } else {
      console.log('Loading data...');
    }
  };
}

const checkDataStatus = fetchData('https://api.example.com/data');
checkDataStatus(); // 可能输出: 'Loading data...'

这里,checkDataStatus 函数是一个闭包,它能访问 fetchData 中的 dataLoaded 变量。

4. 模块模式(Module Pattern)

闭包广泛应用于 JavaScript 模块化开发,用于将变量和方法封装在函数作用域内,避免污染全局作用域。

例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const module = (function() {
  let privateVar = 'I am private';

  function privateMethod() {
    console.log(privateVar);
  }

  return {
    publicMethod: function() {
      privateMethod();
    }
  };
})();

module.publicMethod(); // 输出: I am private

在这个例子中,privateVarprivateMethod 是私有的,外部只能访问公开的 publicMethod。 在 Vue.js 中,闭包的使用并不像在 JavaScript 中直接调用函数时那么显而易见,但仍然有一些地方可以体现闭包的特性,主要体现在事件处理、计算属性、生命周期钩子和组件方法中。以下是 Vue 中一些常见的闭包应用场景:

5. ** Vue事件处理中的闭包**

在 Vue 中,经常会使用事件处理方法。由于 Vue 会自动处理事件绑定,这时方法本身可能会变成一个闭包,能够访问它的外部作用域中的变量。

例如,假设有一个按钮,点击时增加一个计数值:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<template>
  <button @click="increment">Click me</button>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    };
  },
  methods: {
    increment() {
      this.count++;
      console.log(this.count);
    }
  }
};
</script>

在这个例子中,increment 方法是一个闭包,它可以访问 Vue 组件的 data 中的 count 变量,即使该方法是通过 @click 事件触发的。即使 increment 方法和事件处理函数被分离,它仍然能访问到 this.count,因为它保存了对外部作用域的引用。

6. 计算属性中的闭包

计算属性是 Vue 中的一个重要特性,它可以依赖其他数据,并在依赖的数据变化时自动重新计算。计算属性背后也有闭包的实现:每当计算属性被访问时,它会闭包保存相关的响应式依赖,直到计算属性的值被更新。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<template>
  <div>
    <p>{{ doubledCount }}</p>
    <button @click="count++">Increase Count</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    };
  },
  computed: {
    doubledCount() {
      return this.count * 2;
    }
  }
};
</script>

在这个例子中,doubledCount 是一个计算属性,它闭包保存了 this.count 的依赖关系。每当 this.count 发生变化时,doubledCount 会自动重新计算。

7. 生命周期钩子函数中的闭包

Vue 组件中的生命周期钩子,如 createdmountedupdated 等,通常会引用组件的数据或方法,因此它们本质上也是闭包。这意味着即使在组件的生命周期内某些状态发生变化,这些钩子函数仍能访问到组件的上下文。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: "Hello, Vue!"
    };
  },
  mounted() {
    setTimeout(() => {
      this.message = "Hello, World!"; // 这里的箭头函数是闭包
    }, 1000);
  }
};
</script>

这里,mounted 钩子内的箭头函数是一个闭包,它能够访问到 this.message,即使 setTimeout 是异步执行的。

8. 方法中的闭包

Vue 方法(特别是在 methods 中定义的那些)可能会变成闭包,并且这些方法可以访问到组件实例中的所有数据和方法。在异步操作中,闭包特别有用,因为它们能保证访问到正确的上下文(即 this)。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<template>
  <div>
    <p>{{ message }}</p>
    <button @click="delayedChangeMessage">Change message</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: "Initial message"
    };
  },
  methods: {
    delayedChangeMessage() {
      setTimeout(() => {
        this.message = "Updated message";  // 闭包保存了对this的引用
      }, 2000);
    }
  }
};
</script>

这里,delayedChangeMessage 方法内的箭头函数是闭包,它能够引用到 this.message,即使延迟了两秒钟才执行。

9. vue v-for 循环中的闭包

在 Vue 的 v-for 循环中,也可能会使用闭包,尤其是当每个循环项都绑定了事件时。循环中的每个函数都会形成闭包,保存其循环上下文。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<template>
  <div>
    <ul>
      <li v-for="(item, index) in items" :key="index" @click="showItem(index)">
        {{ item }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      items: ['Item 1', 'Item 2', 'Item 3']
    };
  },
  methods: {
    showItem(index) {
      alert('Item index: ' + index);
    }
  }
};
</script>

在上面的代码中,showItem 方法通过 v-for 中的每个 li 元素绑定了事件监听器。每个事件处理程序都是一个闭包,它可以访问到 index 变量,即使这些事件处理函数是在不同的上下文中调用的。

还有没有其他常有的?欢迎各位大佬在评论区留言讨论

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-02-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 农民工前端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
深入理解JavaScript闭包:原理、实践和优化
在JavaScript中,闭包是一个非常重要的概念。它允许函数访问其外部作用域中的变量,即使这些变量在其定义的作用域之外。闭包的出现使得JavaScript能够实现许多高级功能,如模块封装、事件处理、异步编程等。然而,闭包的使用也可能会导致内存泄漏和性能问题。因此,理解闭包的实现原理、实际应用场景以及性能优化技巧对于编写高质量的JavaScript代码至关重要。
Front_Yue
2023/12/16
1.2K0
深入理解JavaScript闭包:原理、实践和优化
Javascript 闭包
一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
超级大帅比
2021/09/05
4270
理解JavaScript闭包机制
JavaScript中的闭包是一种强大的概念,它允许我们在函数内部创建和访问私有变量,并且可以在函数外部继续使用这些变量。理解闭包的工作原理对于编写高质量的JavaScript代码至关重要。本文将深入探讨JavaScript闭包的机制,并结合最佳实践和代码示例进行详细说明。
can4hou6joeng4
2023/11/16
2260
2025最新出炉--前端面试题七
回答: 盒模型是 CSS 布局的核心概念,每个元素都被视为一个矩形盒子,包含以下部分:
全栈若城
2025/02/13
1310
JavaScript闭包
init() 创建了一个局部变量 name 和一个名为 displayName() 的函数。displayName() 是定义在 init() 里的内部函数,并且仅在 init() 函数体内可用。displayName() 没有自己的局部变量。然而,因为它可以访问到外部函数的变量,所以 displayName() 可以使用父函数 init() 中声明的变量 name 。
闲花手札
2021/11/15
6250
前端day20-JS高级(递归和闭包)学习笔记
01-递归 1.1-递归函数介绍 1.递归函数:一个函数自己调用自己 2.递归函数特点 a.一定要有结束条件,否则会导致死循环 b.能用递归函数实现的需求,就一定可以用循环调用函数来解决,只是代码简洁与性能不同而已 递归会影响性能,每一次递归都会进栈容易造成栈溢出,而循环不会 1.2-递归应用场景1(累加和,阶乘) <script> //1.求1-n之间的累加和 function getSum(n){ //递归 : 自己调用自己
帅的一麻皮
2020/05/10
1.3K0
详解JavaScript中闭包(Closure)概念
闭包(Closure)是 JavaScript 中一个非常重要的概念,它允许函数访问其词法作用域(lexical scope)中的变量,即使这个函数在其词法作用域之外执行。理解闭包有助于编写更高效、模块化的代码,并且在处理异步操作、回调函数和数据封装时非常有用。
jack.yang
2025/04/05
770
什么是JavaScript 的闭包???
Javascript的闭包是指一个函数与周围状态(词法环境)的引用捆绑在一起(封闭)的组合,在JavaScript中,每次创建函数时,都会同时创建闭包。闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰,即形成一个不销毁的栈环境。
AlbertYang
2020/09/08
1.2K0
JavaScript闭包深入剖析:性能剖析与优化技巧
在 JavaScript 的奇妙世界里,闭包无疑是一个既强大又迷人的特性。它就像是一把万能钥匙,为开发者打开了实现各种高级功能的大门。从数据封装与保护,到函数的记忆化,再到模块化开发,闭包都发挥着举足轻重的作用。在实际开发中,我们常常利用闭包来创建私有变量和方法,避免全局变量的污染,提高代码的可维护性和安全性。例如,在一个大型的 Web 应用中,我们可以使用闭包来封装一些只在特定模块内部使用的变量和函数,使得外部代码无法直接访问和修改,从而保证了数据的完整性和一致性。
李游Leo
2025/01/31
740
JavaScript闭包深入剖析:性能剖析与优化技巧
《现代Javascript高级教程》Javascript执行上下文与闭包
JavaScript中的闭包源于计算机科学中的一种理论概念,称为“λ演算”(Lambda Calculus)。λ演算是计算机科学的基础之一,1930年由Alonzo Church提出,它是一种用于描述计算过程的数学抽象模型,也是函数式编程语言的基础。
linwu
2023/07/27
1920
JavaScript中闭包详解+举例,闭包的各种实践场景:高级技巧与实用指南
闭包在很多现代编程语言中都存在。常见支持闭包的语言有 JavaScript、Python、Ruby、Swift、Kotlin、Scala 等。本文将着重讲在JavaScript中闭包的常见用法及实操意义。
watermelo37
2025/01/22
1460
JavaScript中闭包详解+举例,闭包的各种实践场景:高级技巧与实用指南
javascript中的闭包closure详解
闭包closure是javascript中一个非常强大的功能。所谓闭包就是函数中的函数,内部函数可以访问外部函数的作用域范围,从而可以使用闭包来做一些比较强大的工作。
程序那些事
2021/03/02
7860
JavaScript进阶教程(5)-一文让你搞懂作用域链和闭包
在JS中变量可以分为局部变量和全局变量,对于变量不熟悉的可以看一下我这篇文章:搞懂JavaScript全局变量与局部变量,看这篇文章就够了 作用域就是变量的使用范围,分为局部作用域和全局作用域,局部变量的使用范围为局部作用域,全局变量的使用范围是全局作用域。在 ECMAScript 2015 引入let 关键字之前,js中没有块级作用域---即在JS中一对花括号({})中定义的变量,依然可以在花括号外面使用。
AlbertYang
2020/09/16
3300
JavaScript进阶教程(5)-一文让你搞懂作用域链和闭包
JavaScript 核心特性之《闭包》
其实闭包这个话题一直也是面试高频题,我在面试当中有 80% 的时候面试官会问我闭包的特性以及实际的应用场景。闭包也确实是 JavaScript 中的核心特性,在实际当中可以说你一直在使用闭包,只不过你并不知道这个是闭包。
离殊
2022/04/01
2830
从闭包和高阶函数初探JS设计模式
JavaScript是一门完整的面向对象的编程语言,JavaScript在设计之初参考并引入了Lambda表达式、闭包和高阶函数等特性。
小东同学
2022/07/29
5450
从闭包和高阶函数初探JS设计模式
闭包
在ES6之前,只有函数可以创建作用域,这里函数foo创建了一个作用域并在该作用域里声明了一个变量a。我们发现,在函数外部是没有办法访问到该变量。作用域的作用之一就是控制变量的访问范围。作用域另外一个作用就是约束了变量的生命周期,也就是说函数执行完毕后作用域内的所有变量都会被销毁
Karl Du
2023/10/20
1810
Vue.js 基础知识内容(前端开发必备)
Vue.js 是一个渐进式的 JavaScript 框架,主要用于构建用户界面。Vue 的核心库只关注视图层,便于与其他库或现有项目集成。与其他框架相比,Vue 更易于学习和使用,适合构建单页应用(SPA)。
繁依Fanyi
2024/06/13
1820
VUE中常用的4种高级特性!
provide/inject 是 Vue.js 中用于跨组件传递数据的一种高级技术,它可以将数据注入到一个组件中,然后让它的所有子孙组件都可以访问到这个数据。通常情况下,我们在父组件中使用 provide 来提供数据,然后在子孙组件中使用 inject 来注入这个数据。
zz_jesse
2024/03/06
2140
VUE中常用的4种高级特性!
再谈JS闭包
在进行闭包讲解之前,我们需要对一些前置知识点,做一些简单的介绍:何为作用域 和 词法作用域。只有在了解了这些概念,我们才会对闭包的认识有的放矢。
前端柒八九
2022/08/25
2.9K0
再谈JS闭包
VUE3.0和VUE2.0语法上的不同
前言:本篇文章只做VUE3.0和VUE2.0语法上的不同分析,不做性能和源码架构等的分析。
javascript艺术
2022/06/08
1.5K0
VUE3.0和VUE2.0语法上的不同
相关推荐
深入理解JavaScript闭包:原理、实践和优化
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档