浅析JavaScript闭包,也许你会有不一样的收获
个人觉得闭包就扯到两个问题:
一是关于函数作用域
二是关于函数最终值的问题
首先聊聊函数作用域
首先,JavaScript有函数作用域,但没有像C#,Java,C++等语言一样有块级作用域的说法。
看看下面的函数 :
JavaScript没有块级作用域
回顾一下,undefined出现的原因大多都是一个变量声明了但是没有赋值(如果变量没有声明会报错的)。很明显这样就很好的解释为什么第一次输出a是undefined了。其实上面这个函数等价于这样书写
输出的结果也是一样的
输出结果也是一样的,所以综上所述:一个函数内声明的变量在JavaScript引擎执行的时候都会把变量
提到最前面。所以说:
无论变量被块级作用域内嵌的有多深,都会把变量提前
再来看闭包,W3C上是这样定义闭包的:
闭包:指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量。
通俗的来说就是函数内部的函数可以访问该函数的变量。
一般来说,一个函数只能访问自己的内部(局部)变量和全局变量,不能访问别的函数里的成员。
但是因为有闭包的存在使得函数内部的函数可以访问该函数外部的变量。下面:
访问c变量的时候报错了
总结一下,一个函数能访问的变量的原则是:从里向外看,能看到的变量都可以访问.
最后看看函数的最终值问题,也是应该特别注意的一点:
先看看下面的函数:
输出10个10
首先定义一个Fun函数,在该函数里面定义一个数组a,for循环为a数组添加一个函数。
所以返回的a数组里面都是函数对象。然后用resule接收这个a数组,如果输出resule[0]则是Function对象;resule[0]()则是输出i的值。也许你会以为会输出0 1 2 3 4 ..但并不是这样的。而输出的都是10。所以可以看出,在JavaScript中函数声明的地方向外看到的变量函数都能访问,并且访问的都是变量的最终值
如果我硬是要让函数输出0、1、2、3、4...挨着输出怎么实现呢?
看看下面的函数:
输出0-9
上面的函数中,我们先要b函数接收每次传来的i值,b函数执行了10次,每次的i值就这b函数的最终值了,所以这样就可以输出我们想要的效果了
闭包问题在JavaScript是一个难点,但闭包在JavaScript中是很有用的。
比如当我需要返回一个局部变量的时候可以在函数里面内嵌一个函数返回;
看下面:
利用闭包访问局部变量
闭包还可以实现私有成员,在这里就不演示了。