对于闭包的深刻理解
来源:互联网 发布:hao123淘宝 编辑:程序博客网 时间:2024/05/01 05:33
闭包(closure),在深刻了解闭包之前,要了解以下知识点:
1、全局变量
2、局部变量
3、作用域:指一个变量的作用范围,本质是一个保存变量的对象(可以叫做作用域对象)
4、作用域链:相当于一个规则,指定了引擎寻找变量的一个顺序
5、执行期上下文栈 ECS(执行环境栈:Execution Context Stack)
6、执行期上下文(EC):也就是执行环境
7、活动对象 AO(Active Object)
闭包产生的条件:
1、受保护的变量和操作变量的函数封装在一个外层函数中定义;
2、外层函数,要将内层函数对象返回;
3、使用者调用外层函数,获得内层函数对象。
闭包的形成过程:
1、在程序执行之前:
产生一个ECS(为了顺序放置所执行函数的EC);首先会向栈中压入主程序main,产生一个全局作用域对象window(该对象中保存着全局变量);其中引用的函数对
象有一个scope属性引用着该全局作用域对象(也就是引用函数来自的作用域对象);
2、在外层函数对象调用时:
产生一个局部作用域对象(也就是一个AO,保存着该函数的局部变量);该AO有一个parent属性指向栈前的一个作用域对象;该AO被内层函数对象的scope属性引
用着;而由于是返回了内层函数对象,所以内层函数是被全局作用域对象所引用着的;
引擎会沿着AO 向parent方向找变量(每个作用域对象连接起来的结构就是作用域链),直到找到为止。
3、当外层函数对象调用后:
本来没有被引用的AO 会在函数调用后而释放,然后垃圾回收。但是现在内层函数对象引用着它,且内层函数被全局作用域对象所引用着,而全局作用域对象是不会
释放的,这就直接导致了内层函数对象不会释放,从而使外层函数的AO被留下来,所以在继续执行(被全局作用域对象引用的)内层函数对象时,作用域链上会多了一
个外层函数对象的作用域。引擎也会经过该作用域查找变量。该作用域上的变量也就被保护起来,一直存在,可以被重用,且不会被污染。
一个经典的setTimeout题目:
for(var i=0;i<5;i++){
setTimeout(function(){
console.log(i);
},1000);
}
将上述代码修改一下:使得运行结果为0,1,2,3,4
解析: 页面中所有的setTimeout都会放在同一个队列中一次执行的(顺序由设定的延迟时间大小所决定的);这个队列需要等到所有可执行代码执行完毕后,才会开始
执行这个队列(不管延迟时间是否为0);所以上述题目中有5个setTimeout被放在队列中,等到可执行代码结束时,i已经为5,所以输出结果会是5个5;这时我们需要用到
闭包,在每次循环时将i保护起来,所以可以如下形成闭包(在外部,或在第一个函数参数处):
1、 for(var i=0;i<5;i++){
(function(i){
setTimeout(function(){
console.log(i);
},1000);
})(i)
}
2、 for(var i=0;i<5;i++){
setTimeout(
(function(i){
return function(){
console.log(i);
}
})(i),1000);
}
可以通过Chrome中的断点查看当运行到内层函数时,形成了闭包将i保护了起来,作用域链上有三个作用域对象。
- 对于闭包的深刻理解
- 对于JS语言的深刻理解(变量定义;作用域链;闭包;this)
- 对于排序的深刻理解
- 深刻理解闭包
- 对于闭包的理解
- [Android]对于Android:Layout_weight的深刻理解
- 闭包的深刻理解,解释很详细
- 谈谈我对闭包知识的深刻理解
- 对于Javascript闭包的理解
- JS闭包之深刻理解
- 深刻理解js执行原理和闭包
- 句柄的深刻理解
- Layout_weight的深刻理解
- 对于c++面向对象的深刻认识和理解--哲学角度看问题(源生论)
- C++对于类访问权限public,protected,private的深刻理解
- 对于分遗产智力题的深刻剖析
- 对String的深刻理解
- 对String的深刻理解
- 求一个大数的平方根
- Mac OS 包管理工具---Homebrew
- for和while/++i和i++
- 向您的项目添加 C 和 C++ 代码 基于Android 2.2已经以上 新姿势 谷歌推荐的最新方式
- 显卡
- 对于闭包的深刻理解
- APP支付报错ALI40247处理方案
- 面试题(JAVA)(一)
- Linux 学习笔记(五) -----帮助命令及压缩与解压
- 用QT实现简单请求登陆界面设计
- Ubuntu 16.04 安装 Docker
- 编码中关于mysql DateTime类型字段的注意事项
- eclipse项目Java路径存储
- JavaScript设置、获取页面url信息