当前位置: 首页 > 科技观察

干货分享:让你分分钟学会javascript闭包

时间:2023-03-18 15:36:42 科技观察

闭包是javascript中特有的概念。对于初学者来说,闭包是一个特别抽象的概念,尤其是ECMA规范给出的定义。如果没有实战经验,你很难从定义上理解它。所以本文不会大篇幅讲述闭包的概念,直接贴干货,让你分分钟学会闭包!1关闭——初恋初体验当我接触到一项新技术时,我首先要做的事情之一就是:找到它的演示代码。对于编码人员来说,代码有时比自然语言更能理解一件事。事实上,闭包无处不在。比如jQuery和zepto的主要代码都包含在一个大的闭包里面,所以我先写一个最简单最原始的闭包demo,让大家脑洞大开生成闭包:functionA(){functionB(){console.log("HelloClosure!");}returnB;}varb=A();b();//HelloClosure!简单,再简单也不是闭包!有了初步了解后,我们再简单分析一下它与普通函数的区别,让我们从“人山人海”中一眼认出“她”。上面的代码翻译成自然语言如下:(1)定义一个普通函数A(2)在A中定义一个普通函数B(3)在A中返回B(4)执行A()并将A的返回结果赋值对变量b(5)执行b(),把这5步总结成一句废话:函数A的内部函数B被函数A外的一个变量b引用,处理完这条废话语句,就变成了closed包的定义:当内部函数被其外部函数外部的变量引用时,就会形成一个闭包。不要刻意记住这个定义。告诉你这个定义的目的是让你明白上面的5步操作是为了解释闭包的定义。因此,当你执行了上面的5个步骤后,你就定义了一个闭包!这是关闭。2闭包的作用在理解闭包的作用之前,我们先了解一下javascript中的GC机制:在javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收,否则这个对象会一直保存在内存中.上面的例子中,B定义在A中,所以B依赖于A,而外部变量b又引用了B,所以A被b间接引用,即A不会被GC回收,会一直存放在内存中中间。为了证明我们的推理,上面的例子稍微改进一下:functionA(){varcount=0;functionB(){count++;console.log(count);}returnB;}varb=A();b();//1b();//2b();//3count在A中是一个变量,在B中改变它的值,每执行一次B,count的值就会在原来的基础上加1。因此,A中的计数始终保存在内存中。这就是闭包的作用。有时我们需要在一个模块中定义这样一个变量:我们希望这个变量一直保存在内存中但不会“污染”全局变量。这时候,我们可以使用闭包来定义这个模块。3高端写法上面的写法其实是最简单最原始的写法,但是在实际应用中,没有人这么玩,尤其是在一些大型的JS框架中。之所以还告诉你这种写法,是因为分心的因素越少,越容易专注于一件事。下面我用通常的写法写了一个简单的demo组件:(child){viewport.appendChild(child);},removeChild:function(child){viewport.removeChild(child);}}window.jView=obj;})(文档);这个组件的作用是初始化一个容器,然后可以在这个容器中添加子容器,也可以移除一个容器。函数很简单,但是这里涉及到另外一个概念:立即执行函数。简单理解一下。主要是理解这种写法是如何实现闭包功能的。上面的代码结构可以分为两部分:(function(){})()红色部分是一个表达式,而这个表达式本身就是一个匿名函数,所以在这个表达式后面加上()就是执行这个匿名函数函数。因此这段代码的执行过程可以分解为:varf=function(document){varviewport;varobj={init:function(id){viewport=document.querySelector("#"+id);},addChild:function(child){viewport.appendChild(child);},removeChild:function(child){viewport.removeChild(child);}}window.jView=obj;};f(document);好像看到了闭包在这段代码有f的影子,但是f里面没有返回值,好像不满足关闭条件,注意这段代码:window.jView=obj;obj是f中定义的一个对象,在这个对象中定义了一系列的方法,执行window.jView=obj就是在window全局对象中定义一个变量jView,并将这个变量指向obj对象,也就是全局变量jView指的是obj。而obj对象中的函数引用了f中的变量viewport,所以f中的viewport不会被GC回收,会一直保存在内存中,所以这种写法满足了关闭的条件。4简单总结这是对闭包最简单的理解。当然,闭包也有更深层次的理解。这涉及到很多。你需要了解JS的执行环境(executioncontext)、活动对象(callobject)以及作用域(scope)和作用域链(scopechain)的运行机制。但是作为初学者,暂时不需要了解这些。有了简单的了解之后,就要在实际项目中使用了。当你用的多了,自然会对闭包有更深的理解!