目录
1、什么是闭包
在前端项目中,闭包的使用场景确实非常广泛。 闭包不仅在面试中被频繁考察,而且在日常开发中也有着重要的应用。
闭包是指能够访问其他函数内部变量的函数。
闭包通常是在一个函数的内部定义的函数,它可以访问到外部函数的局部变量。
2、创建闭包
执行函数时,只要在函数中使用了外部数据,就会创建闭包。
- 在Vue3组件中创建闭包,代码如下:
<template>
<div>
<h1>计算器<h1>
<el-button @click="increment">增加</el-button>
<el-button @click="decrement">减少</el-button>
<p>当前计数:{{ count }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0); //响应式变量
//创建闭包
const increment = () => {
const.value++;
console.log(`增加后的计数:${count.value}`);
};
const decrement = () => {
count.value--;
console.log(`减少后的计数:${count,value}`);
};
</script>
从中,increment 和 decrement 函数都是闭包,因为它们访问了在 setup 函数中定义的 count 变量。在函数中,每次调用 increment 或 decrement 都可以访问和修改同一作用域中的 count 。
- 使用闭包保存状态
有时,希望将某些状态封装在闭包中,以便它们不被外部访问。可以使用返回的对象或者函数来管理这点。
<template>
<div>
<h1>计数器<h1>
<el-button @click="getCount">获取当前计数</el-button>
<el-button @click="reset">重置计数器</el-button>
</div>
</template>
<script setup>
import { ref } from 'vue';
//使用闭包保存状态
const createCounter = () => {
let count = 0; //私有变量
return {
increment() {
count++;
},
decrement() {
count--;
},
getCount() {
return count;
},
reset() {
count = 0; //重置计数
},
};
};
const counter = createCounter(); //创建闭包
//通过闭包方法操作计数器
const getCount = () =>{
alert(`当前计数:${counter.getCount()`};
};
const reset = () => {
counter.reset();
alert('计数器已重置! ');
};
</script>
从中,createCounter 函数返回一个对象,该对象包含方法来操作一个私有 count 变量。这个 count 的值无法被外部直接访问,只能通过闭包提供的公共方式来进行操作。
3、如何销毁闭包
闭包也可能导致内存泄漏,尤其是在某些情况下,闭包保持对不再需要的变量的引用。
以下是一些在 Vue 3 中管理和"销毁"闭包的实践和策略:
-
使用 ref 和 reactive
在 Vue3 中,当你使用 ref 或 reactive 创建响应式数据时,确保当前组件被销毁时,这些状态不会被继续引用。Vue 会自动处理这些响应式对象,因此相对来说,我们不需要特别清理它们,但在使用闭包时要确保没有意外的引用。
-
清理事件监听器和定时器
当使用闭包时,尤其是在使用定时器或事件监听器时,要确保在组件卸载时清理它们,以防止它们继续引用旧的状态。
<template>
<el-button @click="startTime">开始计时</el-button>
</template>
<script setup>
import { ref, onUnmounted } from 'vue';
const count = ref(0);
let timer;
const startTime = () => {
timer = setInterval(() => {
count.value++; //闭包访问
console.log(`计数:${count.value}`);
},1000);
};
onUnmounted(() =>{
clearInterval(timer); //清理计时器,避免闭包引用
});
</script>
从中,setInterval 创建了一个闭包,引用了 count 状态。在组件卸载时,通过 onUnmounted 钩子清理定时器,避免了对 count 的不必要引用。
-
引用的手动管理
如果在方法中使用了闭包,需要确保不再需要这些引用后,显式清理和设置为 null 。
<template>
<el-button @click="startTack">开始任务</el-button>
</template>
<script setup>
import { ref, onUnmounted } from 'vue';
const taskFunction = ref(null);
const startTask = () => {
taskFunction.value = () =>{
console.log("任务进行中");
};
taskFunction.value();
};
onUnmounted(() => {
taskFunction.value = null; //清理引用
});
</script>
重置,当组件被卸载时,taskFunction.value
被设置为 null
,从而释放对其的引用。
-
使用
watch
和computed
中的闭包
在使用 watch
或 computed
时,也要谨慎使用闭包,尤其是在处理异步操作时。确保在操作完成后,适当地清理或重置闭包引用。
4、在 Vue 3 中的闭包的特点和使用场景使用场景
闭包的特点
- 内存管理:
闭包允许保留函数创建时的作用域,这意味着被包含的变量的生命周期会延续超出其外部 函数的执行结束。在适当时机,会保留闭包中引用的变量。
-
数据封装:
闭包可以用于封装变量,隐藏内部状态,外部无法直接访问,而只能通过暴露的函数进行操作。这使得代码更具有模块化和安全性。 -
状态保持:
闭包可以用于保持状态,尤其是在异步编程或者事件处理时,帮助函数保存其调用时的上下文。 -
创建高阶函数:
闭包是实现高阶函数的一种方式,即返回一个函数的函数,具有灵活性。
在 Vue 3 中的使用场景
事件处理:
- 在事件处理函数中,使用闭包来访问组件的响应式状态
<template>
<el-button @click="increment">增加</el-button>
<p>当前计数:{{ count }}</p>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
const increment = () => {
count.value++;
};
</script>
定时器和异步操作:
- 在定时器中使用闭包来访问组件状态,尤其是在定时执行函数时。(代码示例:如何销毁闭包中的清理事件监听器和定时器)
数据封装和私有变量:
- 使用闭包创建私有状态或数据管理函数,不暴露内部实现。
<template>
<el-button @click="getSecret">获取秘密</el-button>
</template>
<script setup>
const createSecret = () => {
const secret = '这是一个秘密';
return () => {
console.log(secret);
};
};
const getSecret = createSecret();
</script>
高阶函数的应用:
- 闭包可以用作高阶函数,避免重复代码。
<template>
<el-button @click="multiplyByTwo()">2乘法结果</el-button>
<el-button @click="multiplyByThree()">3乘法结果</el-button>
</template>
<script setup>
const createMultiplier = (factor) => {
return (num) => num * factor;
};
const multiplyByTwo = createMultiplier(2);
const multiplyByThree = createMultiplier(3);
</script>
组合 API:
- 闭包的机制非常适合 Vue 3 的组合 API,因为它允许您创建强大的、具有自己状态和逻辑的功能。
总结
闭包在 Vue 3 中是一种非常有用的特性,它提高了代码的模块化能力、可维护性和灵活性。通过使用闭包,可以更有效地管理组件内部的状态,处理异步操作,创建私有数据等。理解闭包的工作原理和使用场景将有助于开发更复杂且高效的 Vue 应用程序。
感谢大家的观看,如有不好的地方可以提出建议,喜欢本篇文章可以点个关注以及赞~