JavaScript闭包的个人理解

闭包指的就是内部函数可以访问外部函数的作用域,也就是通过一个函数的子函数来访问这个函数作用域下的变量。

我们可以看一下下面的函数

function Closure() {
    var number = 99;
    function getNum() {
        console.log(number);
    }
    return getNum;
}

var result = Closure();
result();

正常的函数在执行后会被销毁,但是像Closure这样,在执行完var result = Closure()后,Closure并没有被销毁,为什么没有被销毁呢?这就不得不提到另一个概念了——链式作用域。

JavaScript的函数在运行时,使用某个变量时会在当前作用域查找变量,如果没有找到,则会到其上层作用域中寻找。也就是说,父对象的所有变量对其子对象都是可见的,这就是链式作用域

再来看上面的例子,在执行完var result = Closure()后,number 变量仍旧被getNum所引用,而number是在Closure作用域下的,所以Closure也不会被销毁,直到result()执行完之后,才会被销毁。也就是说,在执行result()前,局部变量number会常驻在内存中。

看到这里可能有些人还是有点迷糊,使一个变量常驻在内存中,创建一个全局变量不就好了?可是大家知道全局变量也是有弊端的,全局变量很容易被直接访问并且被修改,如果不小心被修改,可能会造成麻烦。

 

在一些语言中,会使用private来声明私有变量并且暴露一个访问接口来间接访问一个变量,但是JavaScript中没有private,怎么处理呢?答案就是用闭包。使用闭包可以创建类似私有变量的变量,而且不会造成全局变量的污染,但是仍旧会常驻在内存中。

下面是一个闭包私有化变量的示例,可以尝试一下

//闭包的私有化变量
function Person() {
    var money = 100;
    this.makeMoney = function () {
        money ++ ;
        console.log(money)
    }
    this.offer = function(){
        money -- ;
    }
    return this;
}

var person = new Person();
person.makeMoney();

下面是一道闭包的经典面试题及解析,来自于https://blog.csdn.net/qq_24510455/article/details/101778471

function fun(n,o) {
  console.log(o)
  return {
    fun:function(m){
      return fun(m,n);
    }
  };
}
var a = fun(0);  a.fun(1);  a.fun(2);  a.fun(3);
var b = fun(0).fun(1).fun(2).fun(3);
var c = fun(0).fun(1);  c.fun(2);  c.fun(3);
//问:三行a,b,c的输出分别是什么?

解析:首先要明确出现的三个fun函数之间的关系,第一个fun是一个新创建具名函数,第二个fun是一个新创建的匿名函数,第三个被return出去是fun其实是第一个新建的具名函数。

a:fun(0)调用的第一个fun,后面三个a.fun(n)其实调用的都是第一次fun(0)的返回值-匿名fun函数

第一次fun(0) n为0,o没传入,所以undefined

a.fun(1) m为1 n还是0 所以匿名函数调用其实是function(1,0)  第三个fun调用第一个fun, o都是0

所以a输出  undefined,0 ,0, 0

b:fun(0).fun(1)根据a可知输出undefined ,0 ;后面继续调用fun(2) ,由于fun(0)(1)调用使得当前调用还处于第一个fun,所以fun(2)调用到了第二个匿名fun 所以return第三个fun是fun(2,1)也就是第一个fun(2,1);同理到fun(3)的时候第一个fun(3,2)

所以b输出  undefined,0 ,1, 2

c:根据a和b可知,fun(0).fun(1) 和fun(0).fun(1).fun(2)  此时fun(0).fun(1).fun(2) 只是改变了第二个匿名fun的m对于n并没有改变

所以c输出  undefined,0 ,1, 1

你可能感兴趣的:(JavaScript)