拥抱JavaScript闭包
来源:互联网 发布:mac子弹头专柜价格 编辑:程序博客网 时间:2024/05/28 18:44
还记得初学 js 闭包的时候,总觉得他很高深莫测。每次当我觉得我要使用的时候,我都会悄无声息的使用其他的替代方法,只因为我觉得我会好像不会啊!我这样用要是出问题了我必回修改怎么办!不知道大家是不是也有这个感觉,我是这样子的。后来,我慢慢的开始工作的时候,别人总是会提起这个可怕的玩意,搞得我都不怎么想跟他们玩耍,但是时间长了,我觉得我应该花点时间去重新学习一下闭包,不然我发现跟那群 “ 闭包狂魔 ” 们没法玩耍了,于是我就有了如下的个人对闭包的理解。
我是通过《你不知道的JavaScript》的帮助来理解闭包的,还记得作者写到:我马上要传授给你闭包的秘诀 ---> JavaScript中的闭包无处不在,你需要的能够识别并且拥抱他。我看到这句话以后才明白了为什么我身边的然都那么喜欢谈论闭包,因为他无处不在。那么接下来,我们一步一步的去解开为神秘他是无处不在的
首先,我们先来看看什么叫做闭包
我们应该清楚,闭包是产生在函数中的,所以函数调用时:当函数可以记住并访问所在的作用域时,就产生了闭包,即使函数是在当前作用域之外执行。是不是看了这段定义以后感觉都不知道我在干什么,其实我开始看到的时候就是这个感觉,如果这个看不懂,看下面这个闭包的经典案列:
function foo(){ var a = 2 function baz(){ console.log(a) } return baz;}var bar = foo()bar() //2 <---这里就是闭包的效果
这里这个闭包相信大部分人能看出来,下面我们以他为例,来解析一下上面给出的定义。我们一句一句的看,当函数可以记住并访问所在的作用域时,这里说的是记住,并且访问所在的作用域时,上面的例子中,foo 将 baz 作为返回值赋给了bar,执行 bar()等价于执行 baz(),这时,baz是在 foo 外部执行的(满足了即使函数在当前作用域之外执行),但他依然能拿到 a = 2 ,再看定义,记住,baz是不是记住了他的外层 foo 作用域,因为a = 2 是在 foo 的作用域中定义的,所以,baz 满足了记住并且访问所在的作用域,所以baz就叫做闭包。这样子说其实还是不太明确的说法,没关系,我们可以一步一步的解开更深层次的东西。
在这里,我们简单的考虑一下 js 的垃圾回收机制是怎么回收 foo 的作用域的。当我们定义了 foo,在他执行完毕以后,他的作用域(这里指的是他的内部作用域)就会被释放,也就是被回收了。当你在执行了 foo()时,他的作用域就应该被销毁了,但是由于你有执行了bar()(也就是foo 内部的 baz),他要访问 foo 的作用域,这时,就会阻止 foo 的作用域被垃圾回收机制回收,因为 baz 会告诉内存。
由于内部函数 baz 有对 foo 作用域的引用而使得 foo 的作用域没有被回收,这里就是闭包最核心的部分。也就是说,内部函数 baz 保留了对外部函数 foo 作用域的引用的,这个保留的引用就是闭包。
所以这里你应该清楚了,闭包是内部函数保留了对外部函数作用域的引用,所以嘛,深层次的说,这个保留的引用就是闭包。
好了,foo 函数被我们巴拉的时间够长了,但是我不准备放过他,我们继续来巴拉它。
上面讲的例子是不是觉得不是平时你常用的例子,没关系,下面来个你常用的:
function foo(message){ function bar(){ console.log(message) } setTimeout(bar,1000)}foo('Hello 闭包')
现在,我们继续巴拉 foo ,直到我把巴拉 foo 理解闭包这个技能传授给你,如果你已经理解了上面的 “定制化”闭包,那么下面这个你就会很快搞定,废话不多说,我们开搞。
首先当然是定义了一个 foo 函数,接着是经典的 bar ,这次下面是一个计时器函数,在 foo 函数执行 一秒以后,就会执行 bar 函数,打印我们穿进去的参数 message,这里需要说明一下,这个参数也属于 foo 作用域的变量,只是是隐式声明的。这里正常情况下,foo 在执行完以后,作用域就会被销毁,但是由于内部函数 bar 要在一秒后引用 foo 的作用域,他就被保留了下来。在一秒后进行了引用,这个引用就是闭包。是不是这样子有点贴近你的代码了。如果还没有,再看一个例子:
相信作为一个前端你对JQuery一定不陌生,那看完下面这个例子,你就觉得贴近你的代码了:
function setupBot(name, selector) {$( selector ).click( function activator() {console.log( "Activating: " + name );} );}setupBot( "Closure Bot 1", "#bot_1" );setupBot( "Closure Bot 2", "#bot_2" );
下面我们来一次试探性的总结,看看你是不是真的理解了闭包 ---> 内部函数对外部函数作用域的引用。
其实这个总结并不难,难的是你理解的过程,如果你做好准备了,看这句话:将函数当做当做第一级的值类型并到处传递,你就会看到闭包在这些函数里的应用。是不是看完这句话你又从理解变为懵逼了?其实我当时跟你的感觉是跟你一样的,因为这句话说得相当专业。但是我们可以将其翻译成简单点的话,比如下面这样子:将函数当做参数传入另一个函数里或者将函数当做返回值给传出去,如果你这样子干了,你就在使用闭包。有没有被自己的理解力给震惊到,如果你还是云里雾里的感觉,可以看下面的例子:
var b = 2;function aa(){ console.log(b)}setTimeout(aa,1000)
看上面这段代码,是不是闭包呢?你不要急着回答问题,先跟我们之前的定义进行对照。首先 aa 是函数,我们把他当做值传给了定时器,你是不是像起了什么,对,这个是上面闭包的一种情况,然后就是记住并且访问,他记住了吗?其实计时器一秒后就会打印出 2 ,也就是全局变量 b 的值,也就是说 aa 记住了这个存在在全局作用域的 b 的值,并且在需要的时候进行了调用。这里你是不是开始想通了,是不是就是说 aa 取得了全局作用域的引用,我觉得这是废话,因为谁都能引用这个作用域。其实严格意义上来说他并不是闭包,因为全局作用域又不会被回收,因为按照闭包的特性,只要是在全局定义的函数,都会去的这个作用域的应用,并且会像上面定时器一样调用它们,那么这不是就符合了闭包的一切性质,所以和你想的一样,这也算是闭包,你可以这样子理解。
- 拥抱JavaScript闭包
- 拥抱Javascript性能
- 拥抱模块化的JavaScript
- 拥抱javascript的Promise
- 【JavaScript】Javascript闭包
- 抛弃jQuery,拥抱原生JavaScript
- 抛弃jQuery,拥抱原生JavaScript
- 拥抱
- 拥抱
- 拥抱
- javascript的闭包javascript
- Javascript闭包演示javascript
- [ javascript ] javascript闭包测试!
- 【javascript】javascript中的闭包
- 【javascript】学习Javascript闭包
- 拥抱原型面向对象编程JavaScript
- Javascript操作Dom(拥抱native)
- JavaScript!我还是来拥抱你了
- 前端项目实战1:酒仙网首页
- 给自己的mongodb设置密码吧
- angularJS基本表格
- OC学习笔记4
- Leetcode学习(41)—— Find All Anagrams in a String
- 拥抱JavaScript闭包
- 解决 上传的excel2007文件,在用poi处理时通过new XSSFWorkbook(inputStream)出错
- vim
- squid透明代理
- C++ STL--stack/queue 的使用方法
- Ceilometer服务安装和配置
- String index out of range: 0
- Xutils 3.0+数据库操作
- TCP、UDP、IP 协议分析