你不知道的JS---作用域和闭包
2017-08-07 16:13
253 查看
立即执行函数表达式
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、加强封装,可以达到对变量的保护作用
闭包的坏处:浪费内存,闭包中的变量常驻内存,对闭包的使用不当会造成无效内存的产生。
相关文章推荐
- 你不知道的JS-读书笔记(一)--作用域
- JS闭包的作用
- JS作用域函数闭包
- JS教程:词法作用域和闭包
- 深入理解js --作用域与闭包
- JS学习之闭包、this关键字、预解释、作用域综合
- JS教程:词法作用域和闭包
- 你不知道的JS-读书笔记(二)--闭包,模块
- js 闭包作用
- 深入学习js之浅谈作用域(作用域闭包)
- js重点浅谈(跨域,作用域和作用域链,闭包,原型和原型链继承)
- js变量的声明、作用域以及闭包
- 【 js 基础 】【读书笔记】作用域和闭包
- 什么是闭包?在js中的作用是什么?
- JS作用域、作用域链与闭包详解
- 那些年我们一起过的JS闭包,作用域,this,让我们一起划上完美的句号。
- JS高级知识(作用域,作用域链,闭包)
- 变量对象,作用域链,闭包,匿名函数,this关键字,原型链,构造器,js预编译,对象模型,执行模型,prototype继承
- js:深入闭包(作用域:上)
- js:深入闭包(作用域:下)