前端哥今天分享的是关于js中的闭包和匿名函数两者之间的关系,从匿名函数概念到立即执行函数,最后到闭包。下面一起来看看文章分析,希望你会喜欢
本文讲的是关于js中的闭包和匿名函数两者之间的关系,从匿名函数概念到立即执行函数,最后到闭包。下面一起来看看文章分析,希望你会喜欢。 前面讲了一篇在for循环中加setTimeout输出内容,我们用到了一个闭包,但同时也可以说是匿名函数,到底匿名函数和闭包有没有关系呢?【答案是它们之间没有关系】
匿名函数
匿名函数,顾名思义,就是没有名字的函数,与之对应的就是有名字的函数,也叫具名函数。
//匿名函数function (){ console.log('匿名函数');}//具名函数function myFn(){ console.log('具名函数');}//变量a就是匿名函数的名字var a = function(){ console.log('a就是匿名函数的名字');}
如果我们直接在控制台中运行匿名函数,会发现报错,无法执行。匿名函数是无法执行的,一般用到匿名函数的时候都是立即执行,也叫自执行匿名函数或者自调用匿名函数,一般人都叫立即执行函数。
立即执行函数
比较常见的立即执行函数如下:
;(function(){ console.log('caibaojian.com');})();(function(){ console.log('caibaojian.com');}());
上面这两种都是典型的立即执行函数写法,两者的区分就是一个执行在匿名函数括号外面,另外一个发起执行的括号在匿名函数里面。比较常见的是第一种写法,括号在匿名函数的括号外面。
- 首先声明一个匿名函数 function(){alert('我是匿名函数')}。
- 然后在匿名函数后面接一对括号 (),调用这个匿名函数。那为什么还要用一个括号包起来呢?其实是为了兼容JS的语法,如果我们不加括号,直接写成
function (){alert('我是匿名函数')}()
浏览器会报语法错误,想要通过浏览器的语法检查,必须加点小东西,比如下面几种,更多请看:深入js立即调用的函数表达式
(function(){alert('我是匿名函数')} ()) // 用括号把整个表达式包起来(function(){alert('我是匿名函数')}) () //用括号把函数包起来!function(){alert('我是匿名函数')}() // 求反,我们不在意值是多少,只想通过语法检查。 function(){alert('我是匿名函数')}()-function(){alert('我是匿名函数')}()~function(){alert('我是匿名函数')}()void function(){alert('我是匿名函数')}()new function(){alert('我是匿名函数')}()
实际上,立即执行函数的作用只有一个:创建一个独立的作用域,在这个作用域里面,外面访问不到,避免变量污染。比如我们前面的一篇文章,setTimeout的第三个参数里面讲到的一道题目。
for(var i=0;i<6;i ){ setTimeout(function(){ console.log(i); //为什么输出的总是 6,而不是0,1,2,3,4,5 },i*1000);}
我们发现上面这个定时器总是输出6,因为setTimeout里面的执行函数是异步的,执行的时候,i的值是贯穿整个作用域的,而不是单独一个给每个定期器分配了一个i,for运行完的值是6,此时输出就总是6了。 那怎么解决呢?用立即执行函数给每个定时器创造一个独立作用域即可。
for(var i=0;i<6;i ){ (function(j){ setTimeout(function(){ console.log(j); },j*1000); })(i); }
在for循环执行时,立即执行函数就已经有了结果了。而每个立即执行函数里面的j值就是独立的一个,不会受后面影响。所以会分别执行5次定时器。
//第一个立即执行函数(function(0){ setTimeout(function(){ console.log(0); })})(0);//第二个立即执行函数(function(1){ setTimeout(function(){ console.log(1); })})(1);//……//第六个立即执行函数(function(5){ setTimeout(function(){ console.log(5); })})(5);
i 的值从 0 变化到 5,对应 6 个立即执行函数,这 6 个立即执行函数里面的 j 「分别」是 0、1、2、3、4、5。 上面说了这么多关于匿名函数和立即执行函数的,相信你对这两个概念已经很清楚,那么闭包跟匿名函数有关系吗?
闭包
js闭包是指有权访问另一个函数作用域中的变量的函数,个人认为js闭包最大的用处就是防止对全局作用域的污染。闭包最神奇的地方就是能在一个函数外访问函数中的局部变量,把这些变量用闭包的形式放在函数中便能避免污染。更多介绍:浅谈JavaScript中的闭包 我们可以分离出上面的第一个立即执行函数
function box(i){ setTimeout(function(){ console.log(i); },i*1000);}box(1);//或者这样function box(i){ function inner(){ console.log(i); } return inner;}var outer = box(1);outer();
很明显这是一个闭包,然后我们再看看我们最前面的匿名函数代码和立即执行函数代码,可以看出匿名函数和闭包两者并没有关系。闭包既可以在匿名函数也可以在具名函数中使用。 这个for循环中的闭包怎么理解以及自执行匿名函数的作用: 这个for循环产生的闭包其实是定时器的回调函数,这些回调函数的执行环境是window,类似刚才例子中的引用inner的全局outer的执行环境,匿名函数则相当于刚才例子中的box函数。 Stackoverflow网站上的一个提问跟我们今天分析的类似。有一个回答挺好。