JS闭包
来源:互联网 发布:仿京东商城源码 编辑:程序博客网 时间:2024/06/03 19:07
这又是一个老生常谈的js基础问题了,俗话说一千个人眼里有一千个哈姆雷特,同样,一千个人眼里也可能有一千个对闭包的理解,每个人对它的理解都会带一些自己的特色,而这个特色有时候又不太好表达,这就造成了网上对它的介绍实在太多太多,今天我就说一下我对闭包的认识。
闭包是基于词法作用域书写代码时所产生的自然结果,其实可能在你的代码中早已经到处是闭包了,现在缺少的是根据自己的意愿来识别,拥抱和影响闭包的思维环境。
阮一峰老师在博客里说 闭包就是能够读取其他函数内部变量的函数,我觉得说的特别通俗易懂,但也可以稍微扩展一下,这是我在书中看到的,我觉得可能更恰当一些。(阮一峰老师的很多博客都强烈建议新手去看一看,像es6,没有那些晦涩的术语,知识点介绍的也比较清晰,适合大家学习)
当函数可以记住并访问所在的词法作用域,即使函数是在当前词法作用域之外执行,这样就产生了闭包
废话不多说,上 板 栗 ~
先从简单的看
function foo () { var a = 2; function bar () { console.log(a) } return bar;}var baz = foo();baz(); //2 -朋友,这就是闭包的效果
在foo执行后,通常foo()整个内部作用域都被销毁,因为引擎有垃圾回收机制,不再使用的内存空间会被释放,但拜bar()声明的位置所赐,它依然持有对foo内部作用域的引用,拥有涵盖foo内部作用域的闭包,使得该作用域能够一直存活不被释放,这就叫闭包。
接着上板栗
function foo () { var a = 2; function baz () { console.log(a) } bar(baz);}function bar (fn) { fn() //这也是闭包}
无论何种手段将内部函数传递到所在词法作用域之外,他都会持有对原始定义的作用域的引用,无论在何处执行这个函数都会产生闭包。
function wait (message) { setTimeout(function timer (){ console.log(message) },1000)}wait('hello') //这还是闭包
timer具有涵盖wait内部作用域的闭包。
而且,只要使用了回调函数,基本上都有闭包的存在。
循环与闭包
这有一个for循环最常见的例子
for(var i = 1; i<=5; i++){ setTimeout(function timer(){ console.log(i) },i*1000)}
相信大家都能看出来,这段代码最终结果是输出5个6,而不是表面上看到的1到5。
这是为什么呢?
首先,因为js是单线程的,setTimeout会把函数放入执行队列中等待被执行,但队列中在他们前面有for循环,所以函数会等for循环结束后才开始执行,而有因为这些函数用的都是一个作用域内的i,for循环结束时i=6,所以结果为5个6
那如何才能解决这个问题呢
第一种,用立即执行函数(IIFE)
它的原理就是每次循环通过IIFE来创建闭包,这样每次循环时都会记录下当时的内部作用域,每次循环内部作用域都有不同,i都在变,把i传入这个IIFE中,这样内部的函数所引用的i就各不相同了,问题就解决了
for(var i = 1; i<=5; i++){ (function (j){ setTimeout(function timer(){ console.log(j) },j*1000) })(i)}
第二种,块级作用域
es6引入了let声明(具体细节之后再讲,或大家可以先去了解一下),它有个特点是可以统治块级作用域。
回想下我们刚才的方法,我们用IIFE在每次循环生成新的作用域,也可以理解为每次生成一个块作用域,既然这样,我们就可以利用let劫持块作用域,本质上也就是将块转为一个可以被关闭的作用域,每次在里面声明变量,相当于每次循环都生成不同的块作用域,每个块里的东西互不干扰
for(let i = 1; i<=5; i++){ setTimeout(function timer(){ console.log(i) },i*1000)} //就是这么简单的解决了
for循环头部的let还有个特殊的行为,变量在声明过程中不止被声明一次,每次迭代都会声明,随后的每个迭代都会使用上一个迭代结束时的值来初始化这个变量。
今天就先到这里吧~
- js闭包示例
- JS 闭包 计数器
- js闭包
- js 闭包
- js闭包
- js闭包
- js闭包
- js 闭包
- js 闭包
- js闭包
- js闭包
- (function (){})(); JS 闭包
- JS 闭包应用
- js闭包
- JS闭包
- JS 闭包随笔
- js闭包
- js 闭包
- dns服务
- JAVA | 30
- js对excel数据导入和导出数据
- 数据结构学习-二叉树-链式结构、特殊二叉树、性质、遍历、遍历应用
- 简单聊聊Python中的wraps修饰器
- JS闭包
- HTML-布局-浮动-opacity及支持IE6的写法
- windows中批处理文件
- docker 安装gitlab、zentao 禅道、jenkins、svn
- Linux简单入门(一)
- 日记(周末)
- PHP is_uploaded_file()、move_uploaded_file() 函数
- 原生JS实现点击按钮显示更多内容
- shell [ -n ]正确用法