详解JavaScript闭包问题

作者:代码拾荒时间:2026-10-24 12:50:07浏览:188

本文深入解析JavaScript闭包机制,从全局与局部变量作用域入手,阐述如何通过内部函数读取外部变量。重点分析闭包在保留局部变量状态中的应用,并警示滥用闭包导致的内存消耗问题,提供合理的代码优化建议。

闭包是函数式编程语言的核心特性之一。JavaScript将其作为语言基础构件,体现了与函数式编程的紧密联系。因其能简化复杂逻辑,闭包在主流JS库及高质量生产代码中应用日益广泛。

一、变量的作用域

理解闭包前,需先掌握JavaScript的变量作用域机制。JS中的变量作用域主要划分为全局变量和局部变量两类。

1、全局变量


var n = 999; //全局变量

    function f1() {
        a = 100; //在这里a也是全局变量
        alert(n);
    }
    console.log(a); //100

在全局变量场景下,函数内部与外部均可直接访问该变量的值。

2、局部变量


//局部变量
    function f2() {
        var b = 22;
    }
    console.log(b);   //报错

对于局部变量,函数外部无法直接访问在函数内部定义的变量。

那么,若需从外部获取局部变量的值,应如何处理? 请继续阅读后续内容:

二、如何从外部获取局部变量

接下来通过一个具体示例进行说明:


var outer = 'Outer'; // 全局变量
var copy; 
function outerFn(){ // 全局函数
 var inner = 'Inner'; // 该变量只有函数作用域,无法从外部访问
 function innerFn(){ // outerFn()中的innerFn() 
 // 全局上下文和外围上下文都可以在这里使用,
 // 因此可以访问到outer和inner 
 console.log(outer); 
 console.log(inner); 
 } 
 copy=innerFn; // 保存innerFn()的引用
 // 因为copy是在全局上下文中声明的,所以在外部可以使用
} 
outerFn(); 
copy(); // 不能直接调用innerFn(),但是可以通过在全局作用域中声明的变量来调用

分析上述示例:在innerFn()内部可以访问变量outer,因为outer处于全局上下文中。

当outerFn()执行完毕后,通过将该函数的引用复制到一个全局变量 copy中来实现调用。在利用变量copy调用函数innerFn()执行时,此刻已经不在outerFn()的作用域中了。因此下面的代码不是应该失败吗? console.log(inner); 变量inner的值应该是undefined吧?可是,上面代码片段的输出却是: “Outer” “Inner”

这体现了JavaScript的链式作用域结构,子对象会一级一级向上查找所有父对象的变量。因此,父对象的所有变量对子对象都是可见的,反之则不成立。

基于此机制,我们便可以从外部获取函数内部的局部变量。

三、闭包的概念

上述代码块中的copy()函数即为闭包。从概念上讲,闭包是指能够读取函数内部变量的函数。 在JavaScript中,可以通过函数内部的子函数获取到局部变量,因此可以把闭包理解为定义在函数内部的函数。 可以把它理解为一个将函数内部和外部连接起来的桥梁。

四、闭包的作用

在我看来,闭包的作用主要体现在两个方面:

1、可以读取函数内部的变量

这一作用在上个代码块中已得到清晰展现。

2、可以将局部变量的值一直保存在内存中

众所周知,局部变量仅在调用时临时开辟存储空间,函数运行结束后会自动释放。而闭包的出现使得局部变量能像全局变量一样持续存储在内存中。


        function c1() {
            var z = 9999;
            nAdd = function() {
                z += 1;
            }

            function c2() {
                console.log(z);
            }
            return c2;
        }
        var result = c1();
        result(); //9999
        nAdd();
        result(); //10000

在上述代码中,先执行一次c1(),此时z=9999;再执行一次nAdd(),使z+1;在执行一次c1()输出此时z的值,z=10000。说明z的值一直存储在内存中,并没有在第一次调用c1()后背自动消除。

此时就要注意,闭包的使用会消耗很大的内存,不要滥用闭包。在退出函数之前,将不使用的局部变量全部删除。

到此这篇关于详解JavaScript闭包问题的文章就介绍到这了,更多相关JavaScript闭包问题内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

作者最新文章