立即调用的函数表达式(IIFE)

爱总结,爱搬砖,爱生活

引言

偶然之间看到一个问题,问题是这样的:

(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出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面。

JavaScript语言基础教程 --阮一峰

  • 总结一下前面两段话的意思:要让函数定义后能被立即调用,就是要让代码被当作表达式解析,一种解决方法就是加圆括号;
  • 既然括号的作用只是让代码在解析时被解析成表达式,所以文章开头提到的两种写法是没有区别的,不过(function() {}())这种写法更多的被推荐。

不加括号可不可以?

为了避免解析的歧义,JavaScript 规定,如果function关键字出现在行首,一律解释成语句。因此,引擎看到行首是function关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。

JavaScript语言基础教程 --阮一峰

  • 针对文章开头的两种写法不加括号是不可以的,当然还有更多的方法实现函数定义是就调用,这些方式都是被允许的,使用了不同的方式让一个语句变成表示式,这也可以理解为什么叫它立即调用的函数表达式
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))
}

demo链接

参考文章

爱总结,爱搬砖,爱生活

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容