当前位置: 首页 > Web前端 > HTML5

前端优秀教程JavaScript闭包与匿名函数关系详解

时间:2023-04-04 23:40:09 HTML5

前端优秀教程JavaScript闭包与匿名函数关系详解,从匿名函数的概念入手到立即执行函数,最后到闭包。一起来看看文章的分析吧,希望大家喜欢。我讲了在for循环中添加setTimeout输出内容。我们用的是闭包,不过也可以说是匿名函数。匿名函数和闭包有什么关系吗?【答案是没有关系】匿名函数匿名函数顾名思义就是没有名字的函数,与之对应的是有名字的函数,也叫命名函数。//匿名函数function(){console.log('匿名函数');}//命名函数functionmyFn(){console.log('命名函数');}//变量a是匿名函数的名字vara=function(){console.log('a是匿名函数的名字');}如果我们直接在控制台运行匿名函数,会发现错误,无法执行。无法执行匿名函数。通常,当使用匿名函数时,它们会立即执行。它们也称为自执行匿名函数或自调用匿名函数。大多数人称它们为立即执行函数。立即执行函数比较常见的立即执行函数如下:;(function(){console.log('caibaojian.com');})();(function(){console.log('caibaojian.com');}());以上两种是典型的立即执行函数的写法。两者的区别在于,一个在匿名函数括号外执行,一个在匿名函数括号内执行。比较常见的是第一种写法,括号在匿名函数的括号外。步骤分解:1.首先声明一个匿名函数function(){alert('我是匿名函数')}。2、然后在匿名函数后面接一对括号(),调用匿名函数。那为什么要用括号括起来呢?其实就是为了兼容JS的语法。如果我们不加括号,直接写成function(){alert('我是匿名函数')}(),浏览器会报语法错误。如果我们要通过浏览器的语法检查,就必须加点小东西,比如下面的(function(){alert('我是匿名函数')}())//用括号把整个包裹起来expression(function(){alert('我是匿名函数')})()//把函数包在括号里!function(){alert('Iamananonymousfunction')}()//否定,我们不关心值是什么,我们只想通过语法检查。+function(){alert('我是一个匿名函数')}()-function(){alert('我是一个匿名函数')}()~function(){alert('我是一个匿名函数')}()voidfunction(){alert('我是匿名函数')}()newfunction(){alert('我是匿名函数')}()其实立即执行函数只有一个功能:创建一个独立的Scope,在此范围内,外部无法访问,避免变量污染。比如我们上一篇文章中,setTimeout的第三个参数中提到的一个话题。for(vari=0;i<6;i++){setTimeout(function(){console.log(i);//为什么输出总是6而不是0,1,2,3,4,5},i*1000);}我们发现上面的timer一直输出6,因为setTimeout中的执行函数是异步的,在执行的时候,i的值贯穿了整个作用域,而不是单独为每个regular设备分配一个i,for运行后的值为6,此时输出始终为6。如何解决?使用立即执行功能为每个定时器创建一个独立的作用域。for(vari=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闭包最大的用处就是防止对全局作用域的污染。闭包最神奇的地方在于它们可以在函数外访问函数内的局部变量。将这些变量以闭包的形式放在函数中,可以避免污染。我们可以在functionbox(i){setTimeout(function(){console.log(i);},i*1000);}box(1);}box(1);//或这样的functionbox(i){functioninner(){console.log(i);}returninner;}varouter=box(1);outer();结论很明显这是一个闭包,然后我们看一下我们前面的匿名函数代码和立即执行的函数代码,可以看出匿名函数和闭包没有任何关系。闭包可以用在匿名函数和命名函数中。如何理解这个for循环中的闭包以及自执行匿名函数的作用:这个for循环产生的闭包其实就是定时器的回调函数,而这些回调函数的执行环境是window,类似于刚才例子中inner的全局引用outer的执行环境,匿名函数就相当于刚才例子中的box函数。Stackoverflow网站上的一个问题和我们今天分析的类似。有一个答案很好。闭包机制适用于所有JavaScript函数,无论是否匿名。我认为这两个概念之间的混淆来自于使用术语“闭包”,其中作者曾说过“以下代码创建了一个闭包”,然后给出了一个恰好使用匿名函数的示例。在这种情况下,闭包机制通常是使特定代码按预期工作的重要因素,并且使用匿名函数而不是命名函数恰好是一种方便的编码方式。阅读这些示例并第一次看到“闭包”的人会误解该术语,并继续在他们自己的StackOverflow或博客文章中错误地使用它,因此混淆会蔓延。起初我以为匿名函数与闭包有关。那是因为正好这个定时器用到了闭包和匿名函数,让我们误以为两者之间有关系。其实解决这个问题的方法有很多,比如我们之前提到的setTimeout的第三个参数也可以得到和使用立即执行功能一样的效果。所以匿名函数和闭包是没有关系的,但是很多时候用匿名函数解决问题的时候恰好形成了闭包,这让很多人不清楚匿名函数和闭包的关系。