JavaScript闭包
2015-12-23 01:54
387 查看
对于JavaScript闭包问题,一开始,我看了阮一峰老师笔记,感觉也就那么回事,后来在实际开发总也没有遇到太多的闭包上问题.
然而问题永远都是自找的.
我首先遇到的第一个闭包问题是当时面对的setTimeout函数,因为他是一个异步函数,所以闭包可能很容易出现,它的参数模式是这样的:
这里的第一个参数是一个回调函数,第二就是时间,以毫秒计时
他的作用就是在时间过去time ms之后就会调用callback函数
ps:(
函数其实有两种身份
第一种就是函数,可以直接执行的函数.
然而她也可以作为一个对象来传递它的引用,然后执行权交给传递的那个函数对象
因为你直接在他后面加了一个()运算符
)
我的问题就出在了这里
然而在1s后,它输出的是 3
于是怎么也想不明白,如果你也疑惑,那么往下看
好,我们现在开始讨论什么是闭包
我们先给出闭包的定义:
由定义来看闭包有两个部分组成,一个是函数,一个是引用环境,我们再看wiki上的定义:
setTimeout为什么会运行出来3呢,因为返回的函数中绑定了k这个自由变量,这不就是闭包么!
:function(匿名函数)+k(这个自由变量) 离开了创造它的环境也依然存在的变量!
那疑问又来了,为什么会创建一个这样的闭包呢?
我的总结就是,
这个总结其实也符合常理,为什么呢?因为函数的调用离不开他的出生环境,闭包就是为了绑定他的出生环境的作用
ECMAScript5 不支持块级定义域,然而ECMAScript6却支持块级定义域,所以这个总结涵盖了5,6
为什么会这样?(该环境是node.js下测试)
因为var 关键词是不支持块级定义域的,所以,i 只是一个变量因为他只有一个定义域那就是ES5定义域,所以,他们共享一个定义域,所以,他们自由变量自由一个i=10
而let 关键词就不同了,它支持块级定义域,所以每一个i的出生环境都是不同的在不同的for{/*此处为定义域*/},i的变量肯定不同
对于深入浅出node.js这本书,我看到了第四章,其中介绍EventProxy这个开源的时间管理框架的时候,看到了done函数时有感而发写出此文章
然而问题永远都是自找的.
我首先遇到的第一个闭包问题是当时面对的setTimeout函数,因为他是一个异步函数,所以闭包可能很容易出现,它的参数模式是这样的:
setTimeout(callback,time);
这里的第一个参数是一个回调函数,第二就是时间,以毫秒计时
他的作用就是在时间过去time ms之后就会调用callback函数
ps:(
函数其实有两种身份
第一种就是函数,可以直接执行的函数.
然而她也可以作为一个对象来传递它的引用,然后执行权交给传递的那个函数对象
function disporf(callback){ callback(); }如果搞不清这个,setTimeout这个函数你传入值的时候,它会立即执行
因为你直接在他后面加了一个()运算符
)
我的问题就出在了这里
//我先定一个函数 function e(k){ return function(){ console.log(k); } } //然后 setTimeout(e(3),1000);我当时错误的以为,它会输出undefine,因为当我调用完e函数的时候,他的k作为形参,应该会随着他的调用结束而被回收,意思是说k将是一个不存在变量
然而在1s后,它输出的是 3
于是怎么也想不明白,如果你也疑惑,那么往下看
好,我们现在开始讨论什么是闭包
我们先给出闭包的定义:
闭包是由函数和与其相关的引用环境组合而成的实体.
由定义来看闭包有两个部分组成,一个是函数,一个是引用环境,我们再看wiki上的定义:
在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。什么意思呢,联合这两个定义就是说:
闭包=函数+相关的自由变量(这个变量即使离开了定义域也依然存在)
我们给出精确点的定义:闭包有两部分组成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成。</span>我们回看原来我们的问题
setTimeout为什么会运行出来3呢,因为返回的函数中绑定了k这个自由变量,这不就是闭包么!
:function(匿名函数)+k(这个自由变量) 离开了创造它的环境也依然存在的变量!
那疑问又来了,为什么会创建一个这样的闭包呢?
我的总结就是,
当一个函数离开了它定义块,而在定义域外部被调用,便形成了一个闭包.
这个总结其实也符合常理,为什么呢?因为函数的调用离不开他的出生环境,闭包就是为了绑定他的出生环境的作用
ECMAScript5 不支持块级定义域,然而ECMAScript6却支持块级定义域,所以这个总结涵盖了5,6
function ES5(){ for(var i=0;i<10;i++){ setTimeout(function(){console.log(i);},1000); } } function ES6(){ for(let i=0;i<10;i++){ setTimeout(function(){console.log(i);},1000); } } ES5();//10 10 10... ES6();//1 2 3 4
为什么会这样?(该环境是node.js下测试)
因为var 关键词是不支持块级定义域的,所以,i 只是一个变量因为他只有一个定义域那就是ES5定义域,所以,他们共享一个定义域,所以,他们自由变量自由一个i=10
而let 关键词就不同了,它支持块级定义域,所以每一个i的出生环境都是不同的在不同的for{/*此处为定义域*/},i的变量肯定不同
综上所述,也就是说,离开了出生环境,在其出生环境外部被调用的函数,它自身带着出生环境.
对于深入浅出node.js这本书,我看到了第四章,其中介绍EventProxy这个开源的时间管理框架的时候,看到了done函数时有感而发写出此文章
相关文章推荐
- js内置对象
- 说说JSON和JSONP,也许你会豁然开朗
- 利用CSS、JavaScript及Ajax实现图片预加载的三大方法
- Javascript实现图片的预加载的完整实现
- Grails render as JSON输出关联对象各项属性配置
- js实现正则匹配中文标点符号的方法
- 分享JavaScript与Java中MD5使用两个例子
- JavaScript中的函数(二)
- JavaScript对象数组排序函数及六个用法
- JS实现的倒计时效果实例(2则实例)
- 不得不分享的JavaScript常用方法函数集(上)
- javascript新闻跑马灯实例代码
- js判断文本框输入的内容是否为数字
- 使用Function.apply()的参数数组化来提高 JavaScript程序性能的技巧
- js实现图片无缝滚动
- 详解JavaScript时间格式化
- 基于JavaScript代码实现pc与手机之间的跳转
- 超精简的json输出类
- js严格模式
- 反序列化JSON字符串