JS 闭包 p5

终于到闭包了,写了一晚上,好激动:

首先闭包,个人是这样理解的(比较好记):闭包是一种能力,是一种可以访问内部函数作用域的能力或者说是一种行使权力,一旦你拥有这个能力,你将可以访问内部函数的作用域。😵还是有点晕,看例子:

function fn(){
   var a = 2;

   function x(){
       console.log(a);
   }   

  return x;
}

var b = fn();

b();//2

最终结果输出2,fn 函数内部声明了一个x函数,x函数内部访问作用域中的a,之前提到过,a与x函数是fn函数的内部声明,外部是无法访问的,比如直接 x()或者a是会报错的,但是如果我们把x函数当作函数返回给全局作用域中声明的b,

那么b得到了内部函数x的引用,从而获取了可以访问内部声明变量a的能力,或者说涵盖fn内部作用域的使用权利,这种能力或者说叫使用权、访问权就是闭包。

明白没?

另外:因为闭包的存在,垃圾回收器不会回收,因为内部作用域还存在并且被x使用。

再看下面的(书中的例子,拿来):

function fn(){
   var a = 2;
   function foo(){
      console.log(a);
   };  

   out(foo);
}    

function out(f){
   f();   
}

fn(); // 2

 

首先定义了fn函数,然后在其内部定义了一个foo内部函数,最后在fn结尾调用外部的out函数(这个大家都懂,调用外部的函数呗),然后外部函数out形参接收一个函数f(回调函数之前说的),

并调用和执行f(就是foo),奇怪不? 其实和上面的例子道理是一样的,foo这个内部函数拥有了fn内部作用域的闭包或者说能力,在out函数中使用了它,也就是我们说的闭包。所以能够访问fn的内部变量a,最终输出2。

注意的是:关键词是“内部函数”,无论通过何种手段将内部函数传递到所在的词法作用域之外,它都会持有对原始定义作用域的引用。而在执行这个内部函数的引用的时候就会使用到闭包,也就是能力。

或者说闭包是个角色或者是张三,张三看着器材室,你是张三的领导,你需要使用器材,把它叫来,说要篮球,它就给你了。张三就是闭包(不太准确希望你能明白)。

回调函数可以说是最典型的闭包使用者~~

 

再看一个:

// 到百度上试试
var a = document.getElementById('wrapper');
// 添加一个监听事件
a.addEventListener('click',function(e){alert(1)});

是不是明白了?

再来一个:

function x(a){ 
    setTimeout(function timer(){console.log(a)},1000) 
};

x(1);

// 1秒后
// 输出1

 

setTimeout 作为全局作用域的一个函数(window的),timer作为内部函数拥有对x函数内部作用域的行使权,可以访问参数a,且一直持有,当实际调用时,timer行驶了这种权利,访问了a,拿到了篮球~ 这就是闭包。

 

最后一个,这个比较经典(写完回家):

for(var i = 1;i<=5;i++){
  setTimeout(function timer(){console.log(i);},i*1000);
}

最终会输出5次6~,这样也是,下面会一次输出5次6

for(var i = 1;i<=5;i++){
  setTimeout(function timer(){console.log(i);},0);
}

这个是之前在p3里说的吧好像,var i 会在全局作用域或者说外部作用域声明一个 i其实,等到跳出循环的时候 i = 6;

而这里的timer 实际上是拥有了对全局作用域的访问使用权~  而实际上这个i在循环的时候会不停的把这个i重新赋值,一直赋值,直接终止在6上,

虽然timer拥有对i的使用权,但是只会调用最终章,也就是确定后的值,也就是6(因为他们被封闭在一个共享的全局作用域中!

 

那么像实现上面咋整,可以这样:

// 因为立即执行函数IIFE 会创建一个内部作用域
for(var i = 1;i<=5;i++){
  (function(x){   
  setTimeout(function timer(){console.log(x);},0);
  })(i);
  
}

最爽的是这样,用let(之前说了let会独立声明,不会影响外部,是不是最爽了,把var改成let,一劳永逸)

for(let i = 1;i<=5;i++){
  setTimeout(function timer(){console.log(i);},0);
}

 

好了,先写道着~  回家 - -

 

posted @ 2019-01-28 23:35  李鹏飞ONLINE  阅读(146)  评论(0编辑  收藏  举报