揭秘 IIFE 语法

本文讲的是揭秘 IIFE 语法,


只要你稍微接触过一些 JavaScript,你一定会频繁地接触到下面这个模式 —— IIFE,其全称为 immediately invoked function expression,即“立即调用的函数表达式”:

(function() {
    // ...
})();

一直以来,IIFE 创造的函数作用域被用于防止局部变量泄漏至全局作用域中。类似地,我们可以用 IIFE 来包裹私有状态(或广而言之,数据),这两者本质上是相通的。

想知道 IIFE 的更多用途吗,比如提高代码压缩率?不妨看看@toddmotto 的这篇文章

不过,你可能还是会好奇为什么 IIFE 的语法是这样的?它看上去的确有一点点奇怪,让我们一点一点地来揭开她神秘的面纱吧。

IIFE 语法

IIFE 的核心无非就是一个函数,从 function 关键字开始,到右花括号结束:

function() {
    // ...
}

不过,这可不是一段合法的 JavaScript 代码。当 parser(语法分析器)看到这段语句由 function 关键字开头时,它就会按照函数声明(Function Declaration)的方式开始解析了。可是这段函数声明并没有声明函数名,不符合语法规则。因此解析失败,我们只会得到一个语法错误。

所以我们得想个办法让 JavaScript 引擎把它作为*函数表达式(Function Expression)而非函数声明(Function Declaration)*来解析。如果你还不知道这两者的区别,可以看看原作者这篇有关 JavaScript 中不同声明函数方式差异的文章。

我们使用的技巧其实非常简单。用一个圆括号将函数包裹起来其实就可以消除语法错误了,我们得到以下代码:

(function() {
    // ...
});

一旦遭遇到未闭合的圆括号,parser 就会把两个圆括号之间的语句作为表达式来看待。与函数声明相比,函数表达式可以是匿名的,所以上面这段(被圆括号包着的)函数表达式就成为了一段合法的 JavaScript 代码。

如果你想继续了解 ECMAScript 语法,ParenthesizedExpression 这个部分被详细叙述在规范的 12.2 节.

最后剩下的,就是调用这个函数表达式了。目前为止,这个函数还未被执行。我们也没有将它赋值给任何变量 ,因此我们无法持有它的引用从而之后能用来调用它。我们将要做的是在它后面再加上一对圆括号:

(function() {
    // ...
})();

传说中的 IIFE 就这么出现了。如果你稍微回想一下,就会觉得这个名字再合适不过了:一个被立即调用的函数表达式(immediately invoked function expression)

接下来,我们来看几个在不同原因催生下的 IIFE 变种。

圆括号应该放哪?

我们刚才的做法,是把用于调用函数表达式的圆括号直接放在用于包裹的圆括号之后:

(function() {
    // ...
})();

不过,Douglas Crockford 等人觉得悬荡在外的圆括号太不美观了!所以它们把圆括号移到了里面:

(function() {
    // ...
}());

其实两种做法从功能还是语义上来说都差不多,所以选择一种你喜欢的并坚持下去就好了。

实名 IIFE

被包裹起来的函数其实就是个普通的函数表达式,所以你也可以给它个名字让它变成实名的函数表达式

(function iife() {
    // ...
})();

注意你仍然不能省略用于包裹的括号,下面这段代码仍然是无效的:

function iife() {
    // ...
}();

虽然 parser 现在可以成功地把它作为函数声明来解析,但很快,紧跟的 ( 符号就会抛出语法错误了。与函数表达式不同,函数声明并不可以被立刻调用。

避免文件合并时遇到问题

有时,你会看到 IIFE 的前面放了个分号:

;(function() {
    // ...
})();

这个分号被称为防御性分号,用于防止两个 JavaScript 文件合并时可能产生的问题。想象一下假设第一个文件的代码是这样的:

var foo = bar

可以看到这个变量声明语句并没有以分号结尾。如果第二个 JS 文件中的 IIFE 前面没有放分号,合并的结果就会是这样:

var foo = bar
(function() {
    // ...
})();

第一眼看上去好像是一个赋值操作与一个 IIFE。可是事与愿违,我们把 bar 后面的换行去掉就能看清楚了: bar 会被当作一个接受函数类型参数的函数……

var foo = bar(function() {
    // ...
})();

而防御性分号就可以解决这个问题:

var foo = bar;
(function() {
    // ...
})();

就算这个分号前面什么代码也没有,在语法上其实这也是正确的:它会被当做一个空声明(empty statement),无伤大雅。

JavaScript 自动添加分号的特性很容易让意想不到的错误发生。我建议你永远显式地写好分号,以防解释器自己添加。

用箭头函数代替函数表达式

随着 ECMAScript 2015 的到来,JavaScript 的函数声明方式中又多了一个箭头函数(Arrow Function)。箭头函数与函数表达式同属于表达式而非声明语句。所以我们同样可以用它来创造 IIFE:

(() => {
    // ...
})();

不过我并不建议你这么做;我觉得传统的 function 关键字写法的可读性要好得多。





原文发布时间为:2016年04月20日


本文来自合作伙伴掘金,了解相关信息可以关注掘金网站。

时间: 2025-01-26 00:08:52

揭秘 IIFE 语法的相关文章

使用AngularJS编写较为优美的JavaScript代码指南

  本文示例代码下载:modulePattern.zip - 所有的 4 个 HTML 文件 以及 panacea.js - 1.6 KB 介绍 AngularJS 的库里面有很多东西,但本文中我只想专注于小的,针对特定主题的库,我相信通过它们能对Angular有一个较好的介绍. 理解这篇文章并不需要你有任何Angular相关的,甚至是JavaScript的经验.希望你能从本文中看到一些使用Angular的好处,并乐于动手尝试. 背景 我使用Angular有一段时间了,而在学习Angular的时

AngularJS —— 使用模块组织你的代码 【已翻译100%】(1/3)

介绍 AngularJS 的库里面有很多东西,但本文中我只想专注于小的,针对特定主题的库,我相信通过它们能对Angular有一个较好的介绍. 理解这篇文章并不需要你有任何Angular相关的,甚至是JavaScript的经验.希望你能从本文中看到一些使用Angular的好处,并乐于动手尝试. 背景 我使用Angular有一段时间了,而在学习Angular的时候,我也喜欢构建一些样例,所以当我一开始深入进去的时候,对于模块或者JavaScript的设计模式,我也没有多想,那样对保持代码组织和条理性

DMS前后端技术揭秘及最佳实践

不同于一般的存储和计算产品,云上DMS上属于操作类产品,目的是为用户提供更高更强的数据库访问能力,减少成本以提高效率.本文中,来自阿里巴巴数据库事业部的钟隐分享<DMS前后端技术揭秘及最佳实践>,介绍云上DMS,即数据库管理服务的整体应用和实践. DMS最佳实践 云上DMS从2013年年底上线,从最初仅支持MySQL基本功能,已覆盖了多种RDBMS.NoSQL及部分分析型数据库在内的13种数据源,同时在多种数据库中逐步提供了传统数据库软件所不具有的专业功能,时间有限,我们仅列举4个不同角度的最

委托揭秘

参考: 框架设计(第二版):CLR Via C#--15.4 委托揭秘(P281) 正文: 代码1-1,这是一个简单的委托使用. using System; using System.Collections.Generic; using System.Text; namespace Delegate { public class DelegateTest { protected delegate void MyDelegate(); private void TestMethod() { } p

专访实战专家,揭秘iOS神奇开发之路

专访实战专家,揭秘iOS神奇开发之路 转自:http://www.ciitn.com/archive/5533.html 中国信息产业培训网主编专访业内知名实战专家.安博教育-中程在线金牌讲师关东升老师 时间:2012-03-29 10:59来源:未知 作者:xinglu点击: 164 次 在现今的移动互联网时代,苹果产品风靡全球.因此,相应的iOS开发也渐渐成为IT业界热门的职业方向.除了可以给开发人员带来高薪的职位,还能够为个人创造可以盈利的开发模式,对此,中国信息产业培训网主编专访业内知名

JavaScript语法树与代码转化实践

JavaScript 语法树与代码转化实践 归纳于笔者的现代 JavaScript 开发:语法基础与实践技巧系列文章中.本文引用的参考资料声明于 JavaScript 学习与实践资料索引中,特别需要声明是部分代码片引用自 Babel Handbook 开源手册;也欢迎关注前端每周清单系列获得一手资讯. JavaScript 语法树与代码转化 浏览器的兼容性问题一直是前端项目开发中的难点之一,往往客户端浏览器的升级无法与语法特性的迭代保持一致;因此我们需要使用大量的垫片(Polyfill),以保证

浏览器的工作原理:新式网络浏览器幕后揭秘{转}

//我是 "转"的~这么大牛的文章, 我会慢慢理解和回味~ http://taligarsiel.com/Projects/howbrowserswork1.htm http://www.html5rocks.com/zh/tutorials/internals/howbrowserswork/ 浏览器的渲染原理简介 Introduction The browsers we will talk about The browser's main functionality The bro

sql server-“null”附近有语法错误。

问题描述 "null"附近有语法错误. 错误如下: com.microsoft.sqlserver.jdbc.SQLServerException: "null"附近有语法错误. 代码如下: <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page impo

《C++ 黑客编程揭秘与防范》目录—导读

内容提要C++ 黑客编程揭秘与防范本书旨在通过简单的语法知识及常用的系统函数编程,完成一些有特定功能的安全工具,让读者对系统知识等各方面有一个全面的了解,并且在笔者的带领下一步步完成书中的实例.本书主要内容为:第1章了解黑客编程,主要讲解了VC(Visual C++的缩写)和Windwos下安全编程方面的基础知识.第2章 从剖析简单的木马说起,讲解有关的网络编程和协议知识.第3章 Windows应用编程基础,讲解API编程的技术.第4章 加密与解密,讲解PE等加密有关的知识.第5章 HOOK编程