JavaScript闭包详解(全网最细讲解,如果不是。那当我没说hhh)

首先我们得了解一下什么是闭包?
我们看百度词条是这样解释的      
闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。 很显然,几乎了解不了闭包的意思(这里对百度没有任何不好的言论导向),也不知道闭包的有关信息。所以我们从闭包的生成原因来探究 什么是闭包?
1.闭包的形成
首先我们来看其他互联网平台对闭包的解释
闭包:指有权访问另一个函数作用域中变量的函数。
什么是作用域? 当我们声明一个函数的时候,会自动生成一个它的作用域。

例如声明了一个函数fun1() 。我们之前讲过一个概念叫做对象,那么这个fun1()它就是个对象,既然是对象那就有他的属性,在JavaScript引擎中会自动生成一个属性[[scope]],这个玩意叫做作用域,是个隐式属性我们无法去直接调用它,是JavaScript引擎去存取的。

        function fun1(){
            var a = 10;
            console.log(a);
            }

在作用域里面有一个作用域链 scope chain,它是所有执行期上下文对象的集合,呈链式链接;
例如该函数就会生成一个我们看不见的作用域,里面就存取了一个作用域链(scope chain),它的第0位指向Global Object,是全局的一个执行上下文,它存储着一些基本信息,其中就有一个fun1,值为funuction;
然后我们执行这个函数

	fun1();

这个时候系统就会去找fun1的作用域,然后再去找它的作用域链,首先是第0位,是GO(Global Object),在这里之前有个预编译环节,我们先不讲,实际这个时候不是GO。然后我们声明了一个变量a,它也有一个执行期上下文,这里它叫做AO;然后这个AO它就到了第零位(是被该位置的指针指向AO的),而GO在第一位;很显然 这是个 结构,那我们就明白了这个函数的背后逻辑。( 这里补充一下AO里面存的是a,值为10)
我们再看这个函数

        function fun1(){
            var a = 10;
            function fun2(){
                console.log(a);
            }
            return fun2();
        }
        fun1();

按照刚才的逻辑再来一遍,当我们声明fun1的时候会生成它的GO在作用域链的第0位;执行fun1的时候会生成自己的一个AO在第0位,它的GO就到了第二位;这时候fun1的A0里面存着a和fun2 以及它们的值10和function;然后预编译到fun2的时候(注意这里没有执行fun2),fun2是在fun1的AO里面,就相当于fun1的GO;fun2也要生成一个自己的AO,我们叫做AO2;
这时候 fun1的作用域链指向了两个执行上下文分别是第0位的AO和第1位的GO,fun2的作用域链指向了两个执行上下文分别是第0位的AO2和第1位的AO。如下:

函数 执行上下文第0位 执行上下文第1位
fun1 AO GO
fun2 AO2 AO

这个时候在执行fun1,按理来说是不会输出a的值的,因为我们没有执行fun2,但事实是在这里插入图片描述
输出了10。为什么呢?
我们在fun1中定义的局部变量a为什么会被fun2中的语句执行,并且未执行fun2;
这就是闭包产生的效果,当执行完fun1时,它会立即销毁它的执行上下文AO,这时候找不到a的值了;但是fun2的第1位我们可以找到AO;那有疑问了 fun2为什么还有啊?我们说一个函数它的执行上下文是函数执行一次生成一个,执行完立马被销毁,但是,我们压根没执行fun2啊,所以当fun1执行完的时候a已经随着执行上下文AO被销毁了,但是在fun2中的作用域链里的第1位仍指向AO,延长了AO的存在时间。我们再来看这句话 闭包: 指有权访问另一个函数作用域中变量的函数。这里的fun2可以访问fun1里的作用域里的变量a,其实这句话里面省略了 作用域链及指向的执行上下文AO 这就产生了闭包 ;
我们再看几个例子

    function click_times() {
        var i=1;
        return function(){
        alert(i++)
   		}
    }

这个就是利用闭包制作的一个累加器使内部函数的AO一直访问,AO里面有外部函数的变量,也就是说闭包 当内部函数访问外部函数的变量的时候就会产生闭包。
那么如此来看闭包可以做很多事情,但是我们在写JavaScript的代码的时候避免不了产生闭包,那么闭包有什么不好的地方呢?
我们从它的产生原因来看,它的外部函数AO虽然会在该函数执行结束后销毁,它被销毁了,但并没有完全销毁,因为内部函数还是会指向AO,但我们已经用不到它了呀,那它所占的内存没有及时得到释放,就会发生内存泄漏,那当我们不需要闭包的时候,但又不得不产生闭包的时候,该怎么办呢?
                         立即执行函数!

      如何解决闭包问题     详看下期讲解

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>