嗨啊啊啊,首先我要先道歉一下,感觉我很多观念都还没打稳,所以打文章的时候并没有讲解的很清楚,只是想说如果试着去理解,并且打出来和大家分享应该会得到更厉害的大大的建议,当然也是真的有啦!但总觉得如果是这样有点不太好意思,虽然把他归类成笔记,但是既然文章出来了,也是一种技术分享,就觉得应该要更认真的去做好这件事情才行。
另外我也在板上另一个大大fysh711426的文章[Google Code Jam] 2018 资格赛中答应说也要试着来解一下问题,关于这个我原本想说用JavaScript来处理掉,但是现在还没有去处理到这部分,哦怎么觉得从客户那欠东西欠到这里了,不过相信我,我一定会找时间把它处理掉的,如果板上其他大大有兴趣也可以去看一下问题在这里!啊啊啊现在先不要点进去,这篇文章的主题都还没开始,那题外话就不再多说,以下开始!
关于即刻执行函数(immediately invoked function expression),这个不管是中文或是英文都很长,所以大家都简称IIFE,他的意思就如同字面,就是撰写完函式内容后,直接呼叫执行该函数,以下例子:
//一个一般的函式会是以下这样var funcA = function(){ console.log('hello!');};//去执行他funcA(); //会在console中印出'hello!'//而IIFE看起来会是以下这样(function funcB(){ //IIFE的开头 console.log('hello!') //函式内执行的内容}()); //IIFE的结尾//不需要特别去执行就会直接在console中印出hello!funcB(); //但是当我们去做呼叫时会出现「funcB is not defined」的错误,因为在IIFE开头的括号是代表这段程式码是作为一个述句执行里面的运算式,并不是以function去宣告函式,所以他也不会被存在全域变数中,也就不可能呼叫的到了。
接下来继续改写IIFE的内容,IIFE接在函式后右大括号的两个小括号会让函式即刻被执行,也就是说他是靠那个小括号去呼叫的,所以我们可以利用他去加入参数:
//IIFE可以是匿名函式(就是不帮函式取名字),因为他马上就会执行了,之后也不需要再呼叫他,所以有没有名字都无所谓。(function(str){ //我们在这里加入str用来装执行时传入的参数。 console.log(str);}('hello')); //我们把字串'hello'传入IIFE中//不需要执行便会直接在console中印出hello
再来我们看一下IIFE的奇行种,上面第一个例子的最后有提到说,开头的括号是作为一个述句宣告,为了能让里面的程式码变成运算式执行,所以说其实只要能够让该匿名函式变成运算式都能够当成IIFE来使用!例如以下:
//function和上面例子一样,不同的是把原本包着他的括号拿掉,并在前面放一个!运算子!function(str){ console.log(str);}('hello'); //登愣!会发现他还是会在console中印出hello,但是他会回传个结果true,因为!运算子会回传boolean的值,而该函式没有return东西也就是undefined,但是!是Not运算子,所以会把结果从undefined的false转成ture回传,好,这是有点长的题外话,那我们继续看下去。//如果他本身就是在运算子的环境中,甚至不需要再把他变成运算子,例如:var funcA = function(str){ console.log(str); }('hello'); //一样会直接在console中印出hello!
好的,那我们讲了那么多IIFE,但是他到底可以用在什么地方呢?大家应该都知道JavaScript的变数範围有分成全域和区域,IIFE就是为了让全域变数的环境不被全域变数汙染,和在区域中,建立一个新的环境,避免在同个区域内共用同个变数。
让我们看看以下在全域环境使用的例子:
//先建立几个简单的函式function writeStr(str){ console.log(str);};function setValue(){ return 'A'};//在全域中使用var strA = setValue(); //设定strA的值writeStr(strA); //把strA的值交给函式writeStr印出到consolestrA; //会回传'A'因为他已经被存在window,也就是全域环境中了//虽然以上这么做是没问题的,但是全域环境会增加一个strA,这对于依赖全域环境做执行的JavaScript容易出现一些问题,所以我们应该要避免汙染到全域变数,如下://建立IIFE(function(){ var strB = setValue(); //在IIFE中的匿名函式中宣告该变数,他的範围就只会在这个IIFE中,不会汙染到全域环境。 writeStr(strB); //一样把strA丢到函式writeStr印到console上}());strB; //会出现strB is not defined的错误,全域变数没被汙染
最后是在区域中使用的例子:
//建立一个一般的函式,并观察temp在各个地方的变化function funcA(str){ var temp = ''; console.log('(1):' + temp); if(str !== ''){ var temp = str; console.log('(2):' + temp); } console.log('(3):' + temp);};funcA('hello'); //执行后会在console上印出://(1):''//(2):hello//(3):hello//会发现在if内宣告的同名变数temp会在if中设定新的值后,会连整个函式funcA原本的temp值都改变了。//接着在函式内使用IIFE,再观察temp的变化function funcB(str){ var temp = ''; console.log('(1):' + temp); if(str !== ''){ (function(){ var temp = str; console.log('(2):' + temp);}()); } console.log('(3):' + temp);};funcB('hello');//执行后会在console上印出://(1):''//(2):hello//(3):''//可以看到temp这个变数在IIFE中被改变的内容并不会遗留到IIFE外的任何地方,这样就可以避免在同个环境执行时,共用同个变数名称会影响到原本的内容。
以上是对IIFE的一些说明和应用,如果有说明错误或不明白的地方,麻烦再留言告知我,我会尽速改正!!谢谢大家!!