爱总结,爱搬砖,爱生活
引言
偶然之间看到一个问题,问题是这样的:
(function() {}());
(function() {})();
上面这两种写法有没有什么区别?
打眼一看这个问题不太好回答,这说明了一个问题,我对这类立即调用的函数表达式还不熟悉,这个时候应该去百度看看大家怎么理解立即调用的函数表达式。
心得
- 立即调用的函数表达式(在这之前我一直称呼它为立即执行函数,经过此番探索更正了之前不合理的叫法)
- 立即调用的函数表达式的作用:
- 不必为函数命名,避免污染全局作用域;
- 立即调用的函数表达式内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量和方法。
回顾
先从函数的定义和使用说起
// 函数声明
function foo() {
console.log('foo')
}
// 函数表达式
var bar = function() {
console.log('bar')
}
// 调用
foo()
bar()
- 上述两种方式是开发中常用的函数定义和调用方式,回忆一下这两种定义函数的方式;
- 函数声明是会发生函数提升的,允许在定义之前使用
- 函数表达是不会发生函数提升,是不允许在定义之前使用的,函数表达是可以是一个匿名函数(上面这样的),也可以是一个命名函数(下面这样)
// 函数表达式 var rn = function rn() { console.log('rn') }
- 关于函数定义的回顾到此为止,接下来探究立即调用的函数表达式
立即调用的函数表达式
- 文章开头给出的两种写法
(function() {}());
(function() {})();
- 要知道这两种写法有没有区别,那就得先弄清楚为什么会这样写,添上一对括号的作用是什么?不加这对括号可不可以?
括号的作用
函数定义后立即调用的解决方法,就是不要让function出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面。
- 总结一下前面两段话的意思:要让函数定义后能被立即调用,就是要让代码被当作表达式解析,一种解决方法就是加圆括号;
- 既然括号的作用只是让代码在解析时被解析成表达式,所以文章开头提到的两种写法是没有区别的,不过
(function() {}())
这种写法更多的被推荐。
不加括号可不可以?
为了避免解析的歧义,JavaScript 规定,如果function关键字出现在行首,一律解释成语句。因此,引擎看到行首是function关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。
- 针对文章开头的两种写法不加括号是不可以的,当然还有更多的方法实现函数定义是就调用,这些方式都是被允许的,使用了不同的方式让一个语句变成表示式,这也可以理解为什么叫它立即调用的函数表达式
var rn = function rn() { console.log('rn') }();
true && function(){ console.log(1) }();
0, function(){ console.log(2) }();
// 这种方式是被推荐的
!function () { console.log(3) }();
~function () { console.log(4) }();
-function () { console.log(5) }();
+function () { console.log(6) }();
注意:(function() {}())
、(function() {})()
使用这两种写法时,代码所在的上一行代码结束必须有分号,或者写成这个样子;(function() {}())
、;(function() {})()
。
使用场景
- 封装特定功能的模块,起初JQuery就是使用的这种方式;
- 还记得这个案例吗
<button class="btn">0</button>
<button class="btn">1</button>
<button class="btn">2</button>
<button class="btn">3</button>
<script>
var btns = document.getElementsByClassName('btn')
for(var i = 0; i < btns.length; i++) {
btns[i].onclick = function() {
console.log(i);
}
}
</script>
- 上面这个案例中在点击任意按钮的时候打印的都是
4
,原因不必再做解释(使用let声明i变量也可以解决这个问题),现在咱们用立即调用的函数表达式让点击按钮打印不同的值;
// 只贴出了两种解决方式的js代码
// 第一种解决方式
var btns = document.getElementsByClassName('btn')
for(var i = 0; i < btns.length; i++) {
btns[i].onclick = (function(i) {
return function() {
console.log(i)
}
}(i))
}
// 第二种解决方式
var btns = document.getElementsByClassName('btn')
for(var i = 0; i < btns.length; i++) {
(function(i) {
btns[i].onclick = function() {
console.log(i)
}
}(i))
}
参考文章
爱总结,爱搬砖,爱生活