您的位置:首页 > Web前端 > JavaScript

JavaScript闭包

2015-12-23 01:54 387 查看
对于JavaScript闭包问题,一开始,我看了阮一峰老师笔记,感觉也就那么回事,后来在实际开发总也没有遇到太多的闭包上问题.

然而问题永远都是自找的.

我首先遇到的第一个闭包问题是当时面对的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函数时有感而发写出此文章
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: