“javascript没有块级做用域”。所谓“块”,就是大括号“{}”中间的语句。例如if语句:javascript
再好比for语句:html
因此,咱们在编写代码的时候,不要在“块”里面声明变量,要在代码的一开始就声明好了。以免发生歧义。如:前端
在声明变量时,全局代码要在代码前端声明,函数中要在函数体一开始就声明好。除了这两个地方,其余地方都不要出现变量声明。java
javascript除了全局做用域以外,只有函数能够建立做用域。闭包
做用域最大的用处就是隔离变量,不一样做用域下同名变量不会有冲突。函数
做用域只是一个“地盘”,一个抽象的概念,其中没有变量。要经过做用域对应的执行上下文环境来获取变量的值。同一个做用域下,不一样的调用会产生不一样的执行上下文环境,继而产生不一样的变量的值。因此,做用域中变量的值是在执行过程当中产生的肯定的,而做用域倒是在函数建立时就肯定了。spa
因此,若是要查找一个做用域下某个变量的值,就须要找到这个做用域对应的执行上下文环境,再在其中寻找变量的值。htm
在A做用域中使用的变量x,却没有在A做用域中声明(即在其余做用域中声明的),对于A做用域来讲,x就是一个自由变量。以下图blog
在调用函数时,函数中的变量取值要到建立这个函数的那个做用域中取值——是“建立”,而不是“调用”,切记切记!!!ip
第一步,如今当前做用域查找a,若是有则获取并结束。若是没有则继续;
第二步,若是当前做用域是全局做用域,则证实a未定义,结束;不然继续;
第三步,(不是全局做用域,那就是函数做用域)将建立该函数的做用域做为当前做用域;
第四步,跳转到第一步。
例如:在fn函数中,取自由变量x的值时,要到哪一个做用域中取?——要到建立fn函数的那个做用域中取——不管fn函数将在哪里调用
闭包的两种应用场景:函数做为返回值;函数做为参数传递!!!!!!!!
如上代码,bar函数做为返回值,赋值给f1变量。执行f1(15)时,用到了fn做用域下的max变量的值。至于如何跨做用域取值,能够参考上一章。
如上代码中,fn函数做为一个参数被传递进入另外一个函数,赋值给f参数。执行f(15)时,max变量的取值是10,而不是100(由于fn建立做用域是全局做用域,而不是调用的匿名执行函数内)。
第一步,代码执行前生成全局上下文环境,并在执行时对其中的变量进行赋值。此时全局上下文环境是活动状态。
第二步,执行第17行代码时,调用fn(),产生fn()执行上下文环境,压栈,并设置为活动状态。
第三步,执行完第17行,fn()调用完成。按理说应该销毁掉fn()的执行上下文环境,可是这里不能这么作。注意,重点来了:由于执行fn()时,返回的是一个函数。函数的特别之处在于能够建立一个独立的做用域。而正巧合的是,返回的这个函数体中,还有一个自由变量max要引用fn做用域下的fn()上下文环境中的max。所以,这个max不能被销毁,销毁了以后bar函数中的max就找不到值了。
所以,这里的fn()上下文环境不能被销毁,还依然存在与执行上下文栈中。
——即,执行到第18行时,全局上下文环境将变为活动状态,可是fn()上下文环境依然会在执行上下文栈中。另外,执行完第18行,全局上下文环境中的max被赋值为100。以下图:
第四步,执行到第20行,执行f1(15),即执行bar(15),建立bar(15)上下文环境,并将其设置为活动状态。
执行bar(15)时,max是自由变量,须要向建立bar函数的做用域中查找,找到了max的值为10。这个过程在做用域链一节已经讲过。
这里的重点就在于,建立bar函数是在执行fn()时建立的。fn()早就执行结束了,可是fn()执行上下文环境还存在与栈中,所以bar(15)时,max能够查找到。若是fn()上下文环境销毁了,那么max就找不到了。
使用闭包会增长内容开销,如今很明显了吧!
第五步,执行完20行就是上下文环境的销毁过程