796 字
4 分钟

函数闭包

欢迎来到我的博客!#

使用 Markdown 格式编写。

什么是闭包?#

闭包是指一个函数能够访问并记住其词法作用域中的变量,即使该函数在其词法作用域之外执行。

您代码中的闭包实例#

useDog.ts中,getDog函数就是一个典型的闭包:

export default function (){
// 外部作用域的变量
let dogList = reactive([
'https://images.dog.ceo/breeds/pembroke/n02113023_4373.jpg'
])
// 闭包函数 - 可以访问外部作用域的dogList
async function getDog(){
try {
let result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
dogList.push(result.data.message) // 访问外部变量
} catch (error) {
alert(error)
}
}
return {dogList, getDog} // 返回闭包函数
}

闭包的核心特性#

1. 词法作用域访问#

function outer() {
let count = 0; // 外部变量
function inner() {
count++; // 内部函数可以访问外部变量
console.log(count);
}
return inner;
}
const closure = outer();
closure(); // 1
closure(); // 2 - 闭包记住了count的值

2. 变量持久化#

function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter1 = createCounter();
const counter2 = createCounter();
console.log(counter1()); // 1
console.log(counter1()); // 2
console.log(counter2()); // 1 - 每个闭包有自己的作用域

Vue 3组合式API中的闭包应用#

1. 自定义Hooks(如您的useDog)#

useCounter.ts
export function useCounter() {
const count = ref(0);
function increment() {
count.value++; // 闭包访问count
}
function reset() {
count.value = 0; // 闭包访问count
}
return { count, increment, reset };
}
// 组件中使用
const { count, increment } = useCounter();

2. 事件处理器的闭包#

<script setup>
const message = ref('Hello');
// 闭包:setTimeout回调函数可以访问message
function delayedAlert() {
setTimeout(() => {
alert(message.value); // 访问外部作用域的message
}, 1000);
}
</script>

闭包的常见应用场景#

1. 数据封装#

function createPerson(name) {
let age = 0; // 私有变量
return {
getName: () => name,
getAge: () => age,
setAge: (newAge) => age = newAge,
celebrateBirthday: () => age++
};
}
const person = createPerson('张三');
person.setAge(25);
person.celebrateBirthday(); // age变为26

2. 防抖函数#

function debounce(fn, delay) {
let timer = null; // 闭包保存timer
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
const debouncedSearch = debounce(search, 300);

3. 模块模式#

const myModule = (function() {
let privateVar = 0;
function privateMethod() {
return privateVar;
}
return {
publicMethod: function() {
return privateMethod();
}
};
})();

闭包的内存管理#

优点:#

  • 数据封装:创建私有变量
  • 状态保持:函数调用间保持状态
  • 模块化:实现模块模式

注意事项:#

  • 内存泄漏:闭包会阻止垃圾回收器回收外部变量
  • 性能考虑:过度使用闭包可能影响性能

在Vue中的最佳实践#

<script setup>
// 好的实践:使用响应式ref
const count = ref(0);
function increment() {
count.value++; // 闭包访问响应式数据
}
// 避免的实践:直接在闭包中修改DOM
function badPractice() {
setTimeout(() => {
// 避免:直接操作DOM,应该使用响应式数据
document.getElementById('counter').textContent = count.value;
}, 1000);
}
</script>

总结#

闭包是JavaScript中非常重要的概念,它让函数能够:

  • 记住其创建时的词法环境
  • 访问外部作用域的变量
  • 保持状态在多次调用之间

在Vue 3的组合式API中,闭包被广泛应用于自定义Hooks、事件处理等场景,是实现组件逻辑复用的关键技术。

您提供的useDog.ts就是一个完美的闭包应用实例!

赞助支持

如果这篇文章对你有帮助,欢迎赞助支持!

赞助
最后更新于 2026-04-28,距今已过 126 天

部分内容可能已过时

目录