立刻执行函数(Imdiately Invoked Function Expression)到底是什么意思呢?
顾名思义:在该函数定义之后立即被执行的函数。
许多小伙伴应该和我有同样的想法:这不很好操作嘛?操作如下:
function(){
//函数体
}()
//确实符合先定义-function(){},再调用-后面加()
运行结果:报错!----------->(为啥呢?,先定义函数然后调用......问题出现在哪儿了?)
下面就和大家一起探索一下“function和JavaScript引擎解析”之间的奇妙关系~
function关键字,既可以用作语句,也可以用作表达式。如果不加以区分或限定,代码在解析时,就会“不知所措”,分不清是当作语句,还是当作表达式来处理。为了避免这种歧义的产生,JS引擎规定,如果function关键字出现在一行代码的最前部,一律解析为语句。
看到这里,小伙伴应该已经明白上述代码块的报错原因了,可以看到function关键字位于行首,所以JS引擎直接将其当作语句处理,误认为只是函数定义,并不会对此函数产生调用行为。
分不清函数语句和函数表达式的童靴,可以看我的另一篇CSDN博客:
解决方法:
可以用一对括号将整个函数包裹起来,这样function就不在行首了,JS引擎会将其解析为表达式。
括号的使用方法有两种:
//第一种方法,用括号将函数的定义部分包裹起来,再进行调用
(function(){
console.log('于臭臭需要于香香');
})()
//第二种方法,用括号将函数的定义和调用都包裹起来
(function(
console.log('于香香需要于臭臭');
){}())
那么除了用圆括号包裹的形式,能不能用其他符号代替呢?答案是:可以。
//行首添加~符号
~function(){
//函数体
}();
//行首添加+符号
+function(){
//函数体
}();
除了上面显示的两个方式外,还有很多方式,但是作用的原理都是一样的,即:避免function出现在行首,要将function(){]转化为一个可以执行的表达式。虽然有众多的写法,但是用圆括号包裹的方法更加常见,也比较推荐。因为会让代码整体看来更加清晰、整洁。
立即执行函数的用途:
1. “环保性”:从此函数的声明和调用可以看出,我们不需要为函数命名,避免污染全局变量。
2. “私有性”:内部可以形成独立的作用域,将一些变量转化为私有变量,令外部无法访问。
思考题
请尝试运行以下代码,运行结果和你想象中的一样嘛?原因是什么呢?
<ul id="flist">
<li>苹果</li>
<li>香蕉</li>
<li>榴莲</li>
<li>火龙果</li>
<li>荔枝</li>
</ul>
<script>
var ul=document.getElementById("flist")
var list = ul.getElementsByTagName('li');
for (var i=0; i<list.length; i++){
list[i].onclick = function (){
alert(i); //打印出来的i是多少呢?
}
}
</script>
运行结果:5 应该有很多人认为结果应该是0,1,2,3,4
原因解释:i变量是作用于全局范围,并不是for循环每次执行都能得到一个独立的i变量,并没有和每次点击事件进行绑定。再考虑用户点击一定是在for循环完成之后进行的,这时变量已经变成5。
解决方法:思路很简单,只要尝试把i变成独立的变量,每次循环都能创建一个单独的作用域。因此立即执行函数的“私有性”特点能够解决这个问题。代码如下:
for(var i=0; i<list.length; i++){
(function (j){
list[j].onclick = function (){
alert(j);
}
})(i);
}
除此之外,还有其他的方法,例如使用ES6的块级作用域。代码如下:
for(let i=0; i<list.length; i++){
list[i].onclick = function () {
alert(i);
}
}
|
|
|
|
|
|