你不知道的JS---作用域和闭包

xiaoxiao2021-02-28  112

立即执行函数表达式

var a=2; (function foo() { var a=3; console.log(a); })(); console.log(a); 函数被包含在一个括号内部,因此成为了一个表达式,通过末尾加上另外一个括号可以立即执行这个函数。

闭包的定义

当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。

循环和闭包

要想每隔1s输出数字1-5. for(var i=1;i<=5;i++){ setTimeout(function timer(){ console.log(i); }, i*1000); }以每秒一次的频率输出五次6. 原因:延迟函数的回调会在循环结束时才执行,实际情况是 尽管循环中的五个函数是在各个迭代中分别定义的,但他们都被封闭在一个共享的全局作用域中,因此实际上只有一个i。 IIFE会通过声明并立即执行一个函数来创建作用域。 for(var i=1;i<=5;i++){ (function(){ setTimeout(function timer(){ console.log(i); }, i*1000); })(); }但是,通过上面的立即调用函数依然达不到效果,我们的IIFE只是一个什么都没有的空作用域,它需要有自己的变量,用来在每个迭代中储存i的值。 for(var i=1;i<=5;i++){ (function(){ var j=i; setTimeout(function timer(){ console.log(j); }, j*1000); })(); }对上述代码的改进: for(var i=1;i<=5;i++){ (function(j){ setTimeout(function timer(){ console.log(j); }, j*1000); })(i); }在迭代内使用IIFE会为每个迭代都生成一个新的作用域,使得延迟函数的回调可以将新的作用域封闭在每个迭代内部,每个迭代中都会含有一个具有正确值的变量供我们访问。 同样可以实现该功能的代码还有: for(var i=1;i<=5;i++){ let j=i; setTimeout(function timer(){ console.log(j); }, j*1000); } for(let i=1;i<=5;i++){ setTimeout(function timer(){ console.log(i); }, i*1000); } 变量的生命周期 var func=function () { var a=1; return function(){ a++; alert(a); } }; var f=func(); f();//2 f();//3 f();//4 f();//5

当退出函数后,局部变量并没有消失,这是因为当执行var f=func()时,f返回一个匿名函数的引用,可以访问到func()被调用时产生的环境,而局部变量a一直存在这个环境里。

闭包的使用场景

1、函数作为返回值 2、函数作为参数传递 function F1(){ var a=100 return function(){ console.log(a) } } var f1=F1() function F2(fn){ var a=200 fn() } F2(f1)//100

实际开发中闭包的应用

// 闭包实际应用中主要用于封装函数,收敛权限 function isFirstLoad(){ var _list=[] return function(id){ if(_list.indexOf(id)>=0){ return false } else { _list.push(id) return true } } } // 使用 var firstLoad=isFirstLoad() firstLoad(10) firstLoad(10) firstLoad(20)1、封装变量 var mult=(function() { var cache={}; return function(){ var args=Array.prototype.join.call(arguments, ','); if(args in cache){ return cache[args]; } var a=1; for(var i=0,l=arguments.length;i<l;i++){ a=a*arguments[i]; } return cache[args]=a; } })(); 2、延续局部变量的寿命 var report=function(src){ var img=new Image(); img.src=src; }; report('http://xxx.com/getUserInfo') var report=(function(){ var imgs=[]; return function(src){ var img=new Image(src){ var img=new Image(); imgs.push(img); img.src=src; } } })();

闭包的特性:

1、作为函数变量的一个引用,当函数返回时,其处于激活状态

2、闭包就是当一个函数返回时,并没有释放资源的栈区

闭包的原理:

因为闭包只有在被调用时才执行操作,所以它可以被用来定义控制结构,多个函数可以使用同一个相同的环境,这使得他们可通过改变那个环境相互交流

闭包使用场景:

1、采用函数引用方式的setTimeout调用

2、将函数关联到对象的实例方法

3、封装相关的功能

闭包的好处:

1、逻辑连续,当闭包作为另一个函数调用参数时,避免脱离当前逻辑二单独编写额外逻辑

2、方便调用上下文的局部变量。

3、加强封装,可以达到对变量的保护作用

闭包的坏处:浪费内存,闭包中的变量常驻内存,对闭包的使用不当会造成无效内存的产生。

转载请注明原文地址: https://www.6miu.com/read-79692.html

最新回复(0)