神奇的魔法~闭包~必读篇

39 阅读4分钟

闭包(Closure):一个神奇的魔法

闭包大家都不陌生,每个人都对于闭包有或深或浅的认识,本篇就前端闭包一起来聊一聊。 谈到闭包,离不开JavaScript中的作用域作用域链,作用域(Scope)是指变量、函数和对象的可访问性。换句话说,作用域决定了代码中不同部分的变量、函数和对象的可见性。

作用域

  • 全局作用域(Global Scope):在代码任何地方都可以访问;在浏览器中,全局作用域是 window 对象;在 Node.js 中,全局作用域是 global 对象;
var globalVar = "我在全局作用域";

function test() {
    console.log(globalVar); // 可以访问
}

console.log(globalVar); // 可以访问
// - 函数作用域(Function Scope):使用 var 声明的变量具有函数作用域;只能在声明它们的函数内部访问;
function myFunction() {
    var functionScoped = "我在函数作用域内";
    console.log(functionScoped); // 可以访问
}

console.log(functionScoped); // 报错:functionScoped is not defined
// - 块级作用域(Block Scope):使用 let 和 const 声明的变量具有块级作用域;只在 {} 代码块内有效;
if (true) {
    let blockScoped = "我在块级作用域内";
    const constantVar = "我也是块级作用域";
    console.log(blockScoped); // 可以访问
}

console.log(blockScoped); // 报错:blockScoped is not defined
  • 模块作用域(Module Scope):ES6 模块中的变量和函数默认在模块内私有;需要使用 export 导出才能被其他模块访问;
  • 词法作用域(Lexical Scope):函数在定义时就确定了作用域,而不是在执行时;内部函数可以访问外部函数的变量(闭包);
function outer() {
    const outerVar = "外部变量";
    
    function inner() {
        console.log(outerVar); // 可以访问外部变量
    }
    
    return inner;
}

const innerFunc = outer();
innerFunc(); // 输出:"外部变量"

作用域链

当访问一个变量时,JavaScript 引擎会按照以下顺序查找:

  • 当前作用域
  • 外层作用域
  • 全局作用域

综上所述,闭包究竟是在什么?

结合 函数作用域作用域链得出,闭包是函数与其相关的引用环境组合而成的实体

  • 在JavaScript中,闭包:有权访问另一个函数作用域中的变量的函数,扩张变量的作用域范围,局部变量突破了传统的作用域限制,获得了更长的生命周期
  • 即使外部函数已经执行完毕(外部函数已经返回,其执行上下文已经从执行栈中弹出,但是闭包函数(内部函数)仍然可以访问外部函数中声明的变量。这是因为闭包函数的作用域链仍然保持着对外部函数作用域的引用。)。 外部函数已经执行完毕,引出闭包中必须要了解的另外一个概念:js垃圾回收机制 当JavaScript中的作用域链机制。当函数被创建时,它会保存一个作用域链,这个作用域链包含函数被创建时的作用域中的变量对象。因此,即使外部函数执行完毕,其变量对象仍然被内部函数的作用域链引用,所以不会被垃圾回收。而闭包会保留它们的作用域链,所以不会被销毁。
// 正常函数执行流程


function normalFunction() {
    let localVar = '局部变量';
    console.log(localVar);
}

normalFunction();
// 输出: "局部变量"
// 函数执行完毕后,localVar 被销毁,无法再访问



// - 闭包的执行流程

function outerFunction() {
    let outerVar = '我在外部函数中';
    
    function innerFunction() {
        console.log(outerVar); // 访问外部变量
    }
    
    return innerFunction; // 返回内部函数
}

// 关键点在这里!
const closure = outerFunction(); 
// outerFunction 已经执行完毕,按常理 outerVar 应该被销毁

closure(); // 但是这里仍然可以输出: "我在外部函数中"
// outerVar 仍然存在!

简单聊聊闭包的优缺点,感兴趣的话留言评论,大家感兴趣的话可以专门做一篇讲讲优缺点以及实际项目中的运用。

闭包的优点:

✅ 数据封装和私有化

✅ 保持状态和记忆能力

✅ 灵活的函数工厂

✅ 强大的回调处理能力

闭包的缺点:

❌ 潜在的内存泄漏风险

❌ 可能影响性能

❌ 调试复杂度增加

❌ 意外的变量共享问题 谢谢大家观看,走过路过,不要错过了,有钱的捧个钱场,评论区双击666!!! 在这里插入图片描述