JS中的闭包回顾

2020-12-16 11:09发布

在弄明白函数闭包前,先要弄清楚函数执行时的上下文环境。

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
著作权归作者所有,转载请联系作者获得授权,切勿私自转载。