深入理解闭包
一,闭包定义
1. 闭包是指可以访问其所在作用域的函数
那这样说来,需要通过作用域链查找变量的函数就是闭包
1 //按照定义一的说法,需要通过作用域链在全局环境中查找变量n的函数foo()就是闭包 2 var n = 0; 3 function foo() { 4 console.log(n)//0 5 } 6 foo();
2. 闭包是指有权访问另一个函数作用域中的变量的函数
那这样说来,访问上层函数的作用域的内层函数就是闭包
1 nction foo(){ 2 var a = 2; 3 function bar(){ 4 console.log(a); // 2 5 } 6 bar(); 7 } 8 foo();
3. 闭包是指在函数声明时的作用域以外的地方被调用的函数
在函数声明时的作用域以外的地方调用函数,需要通过将该函数作为返回值或者作为参数被传递
3.1 返回值:
1 //按照定义三的说法,在foo()函数的作用域中声明,在全局环境的作用域中被调用的bar()函数是闭包 2 function foo(){ 3 var a = 2; 4 function bar(){ 5 console.log(a); //2 6 } 7 return bar; 8 } 9 foo()();
可简写为如下形式:
1 function foo(){ 2 var a = 2; 3 return function(){ 4 console.log(a);//2 5 } 6 } 7 foo()();
3.2 参数:
1 //按照定义三的说法,在foo()函数的作用域中声明,在bar()函数的作用域中被调用的baz()函数是闭包 2 function foo(){ 3 var a = 2; 4 function baz(){ 5 console.log(a); //2 6 } 7 bar(baz); 8 } 9 function bar(fn){ 10 fn(); 11 }
二,立即执行函数IIFE(Imdiately Invoked Function Expression)
IIFE是不是闭包呢?
foo()函数在全局作用域定义,也在全局作用域被立即调用,如果按照定义一的说法来说,它是闭包。如果按照定义二和定义三的说法,它又不是闭包
1 var a = 2; 2 (function foo(){ 3 console.log(a);//2 4 })();
还有一个更重要的原因是,在requireJS出现之前,实现模块化编程主要通过IIFE,而在IIFE中常见的操作就是通过window.fn = fn来暴露接口,而这个fn就是闭包,而IIFE只是一个包含闭包的函数调用
1 (function(){ 2 var a = 0; 3 function fn(){ 4 console.log(a); 5 } 6 window.fn = fn; 7 })() 8 fn();
严格来说,闭包需要满足三个条件:【1】访问所在作用域;【2】函数嵌套;【3】在所在作用域外被调用
有些人觉得只满足条件1就可以,所以IIFE是闭包;有些人觉得满足条件1和2才可以,所以被嵌套的函数才是闭包;有些人觉得3个条件都满足才可以,所以在作用域以外的地方被调用的函数才是闭包