JS中的闭包

来源:互联网 发布:淘宝客推广员 编辑:程序博客网 时间:2024/06/12 21:47

对闭包的开始的认识是这样的:在函数A中嵌套定义的函数B,会将函数A中的局部变量“包起来”,这样在函数B执行的时候,即可以访问到函数A中的变量值。比如:

function A(){    var aLocal = 3;    return function(){        console.log(aLocal);    }}var B = A();B();//输出3

再抽象点定义就是,函数执行时可以访问在其定义时所处局部环境中的变量。这样理解了很长一段时间,也没觉的不妥,因为基本可以解释实际代码执行的效果。直到遇到这样一段:

var arr = [];function A(){    for(var i = 0;i < 10;i++){        arr[i] = function(){            console.log(i);        }    }}arr[6];//输出9;

按照之前的理解,arr[6]在定义时其所处局部环境变量中i值为6,为何结果是9呢?如何才能实现预期的效果呢?

var arr = [];function A(){    var temp = function(i){        return function(){            console.log(i);        }    }    for(var i = 0;i < 10;i++){        arr[i] = temp(i);    }}arr[6];//输出6;

如何从根本上理解呢?这就要理解js函数的作用域。函数执行时能访问哪些变量,是由函数的作用域决定的,若变量在当前函数的作用域中,则可访问,反之不可访问。

作用域可以理解为一个对象(键值对、哈希表…)。作用域中每个可访问的变量名都是该对象的一个键。js的函数的作用域不是一个单独的作用域对象构成的,而是作用域链,即由多个作用域对象依次串联。

函数执行中要访问一个变量时,先从最近的一个作用域对象中查找,若找不到则从上一个作用域对象中查找,直到找到该变量定义或找完作用域链上的所有作用域对象。

那么作用域链是如何形成的呢?首先,函数被定义时所处的作用域链(全局函数被定义时作用域链中只有全局对象,比如window。在函数A中嵌套定义的函数B被定义时所处的作用域链即函数A执行时的作用域链)将作为函数的初始作用域链被函数保存。其次,当函数执行时,形参及函数内的局部变量又构成了一个作用域对象,并被拼接到初始作用域链中。至此形成函数执行时完整作用域链。

据此分析代码2,当函数A执行时,A的形参(无)和局部变量(i)形成了A的作用域对象SA(省略描述A执行时完整作用域链),定义arr[i]时,arr[i]会将SA作为初始作用域链保存,无论i是几,arr[i]保存的初始作用域对象都是SA,故在arr[i]执行时,均在SA中找到变量i的定义,而此时SA中i的值为9;

据此分析代码3,每次定义arr[i],都是通过一次temp函数的执行。每次temp函数执行时都形成一个执行时作用域对象(由形参i构成)Si,Si作为初始作用域链被arr[i]保存,所以,arr[i]中保存的Si是不同的对象,每个对象中i的值都是temp执行时的形参值。

ES6中增加块作用域的概念后,作用域对象不仅限于函数执行时形参和局部变量形成的对象,还会有更小力度的块作用域对象。但是作用域链的概念和闭包形成的原理还是一致的。

0 0
原创粉丝点击