在弄明白函数闭包前,先要弄清楚函数执行时的上下文环境。
console.log(fn); var fn = function(){ //函数表达未 return 55; } //打印 undefined console.log(fn); function fn(){ //函数声明 return 55; } //打印 /* ƒ fn(){ return 55; } */
在全局环境下,由于有变量提升这个机制在,所以在执行上下文环境中,数据体现的不尽相同:
变量、函数表达示 ———— 变量声明,默认赋值为 undefined
this ———— 赋值
函数声明 ———— 赋值
而在函数体环境中,函数体内的arguments
变量和函数的参数都已经被赋值,函数每次调用,都会创建一个新的上下文环境,因为不同的调用可能会有不同的参数。
function fn(x){ console.log(arguments); // [10] console.log(x); // 10 } fn(10)
但是注意在函数定义(不是调用)的时候,就已经确定了函数体内部自由变量的作用域。
var x = 22; function fn(){ console.log(x); //x是自由变量,在函数fn创建时就确定了x要取值的作用域 } function fn2(f){ var x = 50; f(); //打印22,而不是50 } fn2(fn)
给执行上下文环境下个通俗的定义:在执行代码前,把将要用到的所有变量都事先拿出来,有的直接赋值了,有的先用undefined
占个空。
关于作用域,需要知道JS中没有块级作用域,此外还需要注意JS除了全局作用域外,只有函数可以创建局部作用域。
作用域的概念比较抽象,可以理解为“地盘”,看下图:
图1
上图所示,全局代码和fn、bar两个函数都会形成自己的作用域。而且,作用域有上下级关系,上下级关系的确定就看函数是在哪个作用域下确定的。例如,fn作用哉下创建了bar函数,那"fn作用域"就是"bar作用域"的上级。
作用域最大的作用就是隔离变量,不同作用域下同名变量不会有冲突。
这里再补充个自由变量的概念:在某个作用域中使用的变量X,却没有在该作用域中声明(换句话说就是变量X是在其他作用域中声明的),对于该作用域来说,这个变量X就是自由变量。那么这个自由变量X的取值又该怎么取呢?记住:要到创建这个函数的作用域中去取值,举例如下。
var x = 10; function fn1(){ console.log(x) } function fn2(f){ var b = 20; (function(){ f(); //打印10,而非20 })() } fn2(fn1)
了解上下文环境和作用域,就可以比较顺畅的理解闭包了。闭包通常有两个应用场景:函数作为返回值、函数作为参数传递。
1、函数作为返回值:
function fn(){ var max = 10; return function bar(x){ if(x>max){ console.log(x); //20 } } } var f1 = fn(); f1(20)
上例中,闭包函数bar就是作为返回值。当执行到f1(20)
时,在闭包函数bar中max作为自由变量是跨域取值的,还记得怎么跨域取值么?要到创建这个函数的作用域中去取
2、函数作为参数传递
var max = 10, fn = function(x){ if(x > max){ console.log(x); } }; (function(f){ var max = 100; f(15); //15 })(fn);
上例中,函数fn就是作为参数传递到自执行匿名函数中去的,在执行f(15)
时,作为参数传递进去的fn函数中的自由变量max取的值是10而非100,原因也是在于:自由变量的取值是要到创建这个自由变量所在函数的作用中去取的。
作者:一期一会
链接:https://blog.csdn.net/qq_34832846/article/details/86062158
来源:CSDN
著作权归作者所有,转载请联系作者获得授权,切勿私自转载。