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(); }
; // 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); }
好了,先写道着~ 回家 - -