1. 定义
IIFE: Immediately Invoked Function Expression,意为立即调用的函数表达式,也就是说,声明函数的同时立即调用这个函数。
对比一下,这是不采用IIFE时的函数声明和函数调用:

function foo(){
var a = 10;
console.log(a);
}
foo();

下面是IIFE形式的函数调用:

(function foo(){
var a = 10;
console.log(a);
})();

函数的声明和IIFE的区别在于,在函数的声明中,我们首先看到的是function关键字,而IIFE我们首先看到的是左边的(。也就是说,使用一对()将函数的声明括起来,使得JS编译器不再认为这是一个函数声明,而是一个IIFE,即需要立刻执行声明的函数。
两者达到的目的是相同的,都是声明了一个函数foo并且随后调用函数foo。

2. 为什么需要IIFE?
如果只是为了立即执行一个函数,显然IIFE所带来的好处有限。实际上,IIFE的出现是为了弥补JS在scope方面的缺陷:JS只有全局作用域(global scope)、函数作用域(function scope),从ES6开始才有块级作用域(block scope)。对比现在流行的其他面向对象的语言可以看出,JS在访问控制这方面是多么的脆弱!那么如何实现作用域的隔离呢?在JS中,只有function,只有function,只有function才能实现作用域隔离,因此如果要将一段代码中的变量、函数等的定义隔离出来,只能将这段代码封装到一个函数中。
在我们通常的理解中,将代码封装到函数中的目的是为了复用。在JS中,当然声明函数的目的在大多数情况下也是为了复用,但是JS迫于作用域控制手段的贫乏,我们也经常看到只使用一次的函数:这通常的目的是为了隔离作用域了!既然只使用一次,那么立即执行好了!既然只使用一次,函数的名字也省掉了!这就是IIFE的由来。

3. IIFE的常见形式
根据最后表示函数执行的一对()位置的不同,常见的IIFE写法有两种,示例如下:
列表1:IIFE写法一

(function foo(){
var a = 10;
console.log(a);
})();

列表2:IIFE写法二

(function foo(){
var a = 10;
console.log(a);
}());

这两种写法效果完全一样,使用哪种写法取决于你的风格,貌似第一种写法比较常见。
其实,IIFE不限于()的表现形式[1],但是还是遵守约定俗成的习惯比较好。

4. IIFE的函数名和参数
根据《You Don’t Know JS:Scope & Clouses》[2]的说法,尽量避免使用匿名函数。但是IIFE确实只执行一次,给IIFE起个名字有些画蛇添足了。如果非要给IIFE起个名字,干脆就叫IIFE好了。
IIFE可以带(多个)参数,比如下面的形式:

var a = 2;
(function IIFE(global){
var a = 3;
console.log(a); //
console.log(global.a); //
})(window); console.log(a); //

5. IIFE构造单例模式
JS的模块就是函数,最常见的模块定义如下:

function myModule(){
var someThing = "123";
var otherThing = [1,2,3]; function doSomeThing(){
console.log(someThing);
} function doOtherThing(){
console.log(otherThing);
} return {
doSomeThing:doSomeThing,
doOtherThing:doOtherThing
}
} var foo = myModule();
foo.doSomeThing();
foo.doOtherThing(); var foo1 = myModule();
foo1.doSomeThing();

如果需要一个单例模式的模块,那么可以利用IIFE:

var myModule = (function module(){
var someThing = "123";
var otherThing = [1,2,3]; function doSomeThing(){
console.log(someThing);
} function doOtherThing(){
console.log(otherThing);
} return {
doSomeThing:doSomeThing,
doOtherThing:doOtherThing
}
})(); myModule.doSomeThing();
myModule.doOtherThing();

6. 小结
IIFE的目的是为了隔离作用域,防止污染全局命名空间。
ES6以后也许有更好的访问控制手段(模块?类?),有待研究。

引用
1.Ben Alman, “Immediately-Invoked Function Expression (IIFE)“.
2.Kyle Simpson, You Don’t Know JS:Scope & Clouses (, 2014).

原文地址:http://softlab.sdut.edu.cn/blog/subaochen/2016/02/说一说js的iife/

说一说JS的IIFE的更多相关文章

  1. JS的IIFE

    1. 定义 IIFE: Immediately Invoked Function Expression,意为立即调用的函数表达式,也就是说,声明函数的同时立即调用这个函数. 首先我们要了解一般情况下什 ...

  2. 学习rollup.js模块文件打包

    学习rollup.js模块文件打包 一:rollup 是什么?Rollup 是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码. webpack 和 Rollup 对比不同点 ...

  3. Vue 2.0 入门系列(15)学习 Vue.js 需要掌握的 es6 (2)

    类与模块 类 es6 之前,通常使用构造函数来创建对象 // 构造函数 User function User(username, email) { this.username = username; ...

  4. 深入学习rollup来进行打包

    深入学习rollup来进行打包 阅读目录 一:什么是Rollup? 二:如何使用Rollup来处理并打包JS文件? 三:设置Babel来使旧浏览器也支持ES6的代码 四:添加一个debug包来记录日志 ...

  5. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十六 ║Vue基础:ES6初体验 & 模块化编程

    缘起 昨天说到了<从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十五 ║ Vue前篇:JS对象&字面量&this>,通过总体来看,好像大家对这一块不是很 ...

  6. rollupjs 基本试用

    备注:    前端构建工具   1. 安装 yarn global add rollup yarn global add rollup 2. 基本使用 touch index.js index.js ...

  7. Rollup 配置 es6 环境

    前 为了可以使用新型的语法,顺便在兼容下老的浏览器,所以需要自己搭建个环境,目前我个人推崇使用 rollup,主要喜欢它的 tree-shake,打包出来的代码真的很简洁. 配置 rollup.con ...

  8. 实用程序包utils - 基于Rollup打包输出各模块文件(二)

    上一次,我们讲到了如何去搭建一个前端工具库的工程,那么今天我们来聊一聊如何去将其打包输出. 需求 事情是这个样子的.我有一个这样的需求,或者是我发现有这么一个需求.就是有时候吧,我也不想搞的那么复杂, ...

  9. 使用 vite 构建一个表情选择插件

    初始化 Vite 基于原生 ES 模块提供了丰富的内建功能,开箱即用.同时,插件足够简单,它不需要任何运行时依赖,只需要安装 vite (用于开发与构建)和 sass (用于开发环境编译 .scss ...

随机推荐

  1. 为什么redis是单线程的以及为什么这么快?

    官网的说法 我们先来认真看一下官网的说法.翻译过来大意如下: CPU并不是您使用Redis的瓶颈,因为通常Redis要么受内存限制,要么受网络限制.例如,使用在一般Linux系统上运行的流水线Redi ...

  2. 在同一个服务器上同时配置xxxxxxxxxx1个tomcat

    下面我们把配置的详细过程写在下面,以供参考:(此例以配置三个Tomcat为例) 下载apache-tomcat-7.0.63,下载下来的文件为apache-tomcat-7.0.63.zip. 解压该 ...

  3. 十七, Oracle索引约束

    管理索引-原理介绍 索引是用于加速数据存取的数据对象.合理的使用索引可以大大降低i/o次数,从而提高数据访问性能. 单列索引 适当的索引对于大型数据库的性能有不错的提升, 但在创建索引时要小心.选择字 ...

  4. JVM原理与深度调优(三)

    jvm垃圾收集算法 1.引用计数算法每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收.此方法简单,无法解决对象相互循环引用的问题.还有一个问题是如何解决精准计 ...

  5. Spring Cloud 系列之 Stream 消息驱动(一)

    在实际开发过程中,服务与服务之间通信经常会使用到消息中间件,消息中间件解决了应用解耦.异步处理.流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构. 不同中间件内部实现方式是不一样的,这些中间 ...

  6. history of program atan2(y,x)和pow(x,y)

    编年史 1951 – Regional Assembly Language 1952 – Autocode 1954 – IPL (LISP语言的祖先) 1955 – FLOW-MATIC (COBO ...

  7. Pycharm中设置encoding

    在Pycharm专业版中,为了防止文件在别的机器上出现乱码,所以需要进行字符编码的设置. 首先在Pycharm中的View中将下图中的Toolbar打上勾. 接着,工具栏就会出现,选中settings ...

  8. 【Linux网络基础】 DNS:介绍、作用、解析原理

    1. DNS是什么?   DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去+·记住能够被机器直接读 ...

  9. 工具 在 Nuget 发布自己的包

    MSDN : https://docs.microsoft.com/zh-cn/nuget/quickstart/create-and-publish-a-package-using-visual-s ...

  10. BlackNurse攻击:4Mbps搞瘫路由器和防火墙

    研究人员宣称,最新的知名漏洞BlackNurse,是一种拒绝服务攻击,能够凭借仅仅15到18Mbps的恶意ICMP数据包就将防火墙和路由器干掉. 该攻击会滥用Internet控制报文协议(ICMP)第 ...