Open felix-cao opened 5 years ago
Imdiately Invoked Function Expression,简称IIFE,中文意思是立即执行函数,也叫自执行函数,声明一个匿名函数,马上调用这个匿名函数。也可以说成,立即执行函数是一种语法,可以让你的函数在定义以后立即被执行。
Imdiately Invoked Function Expression
IIFE
用于创建独立的作用域,封装一些临时变量或者局部变量,避免了污染全局变量。
这也是后来 CommonJS 和 ES6 都纷纷提出模块化的原因,请阅读:
CommonJS
ES6
立即执行函数的写法分三步走:
function() {console.log('匿名')}
JS
在《JavaScript 圆括号操作符和void操作符》一文中我们知道是:把函数放在()里会返回函数本身,如果圆括号紧跟函数后面表示调用函数,即对函数求值。
()
上面的第二步为什么要用圆括号括起来,这是为了兼容 JavaScript 定义的语法规则。 不能在函数的定义后面直接加圆括号,这会产生语法错误。
JavaScript
function() {console.log('匿名')} () // 报错
产生这个错误的原因,function 这个关键字既可以当做语句,也可以当做表达式。
// 语句 function fn() {}; // 表达式 var fn = function (){}
为了避免解析上的歧义,javascript 引擎规定,如果 function 关键字出现在行首,一律解释成语句。因此,javascript 引擎看到行首是 function 关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。
javascript
function
解决方法就是不要让 function 出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里。
最常用的两种办法
(function(){ /* code */ }()); (function(){ /* code */ })();
其他写法
var i = function(){ return 10; }(); true && function(){ /* code */ }(); 0, function(){ /* code */ }(); !function(){ /* code */ }(); ~function(){ /* code */ }(); -function(){ /* code */ }(); +function(){ /* code */ }(); new function(){ /* code */ }; new function(){ /* code */ }();
JavaScript 中是没有块级作用域的(直到 ES6, 增加了 let, const),立即执行函数也可以看做是模仿了块级作用域的实现
let
const
(function(){ //这里是块级作用域 })();
面向对象编程语言的对象有三大特性,分别是多态、继承、封装,封装的主要目的是隐藏数据。在类式编程语言中,一般都提供 private, protected, public关键词来修饰类的属性与方法,从而决定是否隐藏,但是 JavaScript 并没有类的概念,它的封装就是通过立即执行函数来实现的。
private
protected
public
我们用一个案例来更直观地说明 IIFE 的用途:假设有一个需求,每次调用函数,都返回加1的一个数字(数字初始值为0),下面给出三种实现方式。
一般情况下,我们会使用全局变量来保存该数字状态
var a = 0; function add(){ return ++a; } console.log(add()); // 1 console.log(add()); // 2
但上面的方法中,变量 a 实际上只和 add 函数相关,却声明为全局变量,不太合适。
a
add
将变量 a 更改为函数的自定义属性更为恰当
function add(){ return ++add.count; } add.count = 0; console.log(add()); // 1 console.log(add()); // 2
函数也是对象,对象可以动态添加属性和方法。
上面的方法还是有问题,有些代码可能会无意中将 add.count 重置。
add.count
使用 IIFE 把计数器变量 count 保存为私有变量更安全,同时也可以减少对全局空间的污染
count
var add = (function(){ var count = 0; // private return function(){ return ++count; } })(); console.log(add()); // 1 console.log(add()); // 2
需要注意的是这里有一个语法坑:
var a = function(){ return 1; } (function(){ console.log(a()); // 报错 })();
这是因为第三行没有加分号,浏览器将上面代码解释成如下所示
var a = function(){ return 1; }(function(){ console.log(a()); // 报错 })();
如果加上分号,就不会出错了
var a = function(){ return 1; }; (function(){ console.log(a()); // 1 })();
立即执行函数也是函数,是函数就可以带参数。
var age = 18; (function($){ console.log('my age is: ',$) })(age); // my age is: 18
把全局作用域下声明的 age 作为匿名函数的参数,匿名函数用变量 $ 接收。
age
$
3.3 就是利用了立即执行函数返回一个函数。
var age = 18; var fn = (function($){ return function() { console.log('my age is: ',$) } })(age); fn() // my age is: 18
一、 概述
1.1、 概念
Imdiately Invoked Function Expression
,简称IIFE
,中文意思是立即执行函数,也叫自执行函数,声明一个匿名函数,马上调用这个匿名函数。也可以说成,立即执行函数是一种语法,可以让你的函数在定义以后立即被执行。1.2、 用途
这也是后来
CommonJS
和ES6
都纷纷提出模块化的原因,请阅读:二、写法
立即执行函数的写法分三步走:
function() {console.log('匿名')}
JS
的语法在《JavaScript 圆括号操作符和void操作符》一文中我们知道是:把函数放在
()
里会返回函数本身,如果圆括号紧跟函数后面表示调用函数,即对函数求值。2.1、为什么这么写?
上面的第二步为什么要用圆括号括起来,这是为了兼容
JavaScript
定义的语法规则。 不能在函数的定义后面直接加圆括号,这会产生语法错误。产生这个错误的原因,function 这个关键字既可以当做语句,也可以当做表达式。
为了避免解析上的歧义,
javascript
引擎规定,如果function
关键字出现在行首,一律解释成语句。因此,javascript
引擎看到行首是function
关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。解决方法就是不要让
function
出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里。最常用的两种办法
其他写法
2.2、块级作用域
JavaScript
中是没有块级作用域的(直到ES6
, 增加了let
,const
),立即执行函数也可以看做是模仿了块级作用域的实现三、用途分析
面向对象编程语言的对象有三大特性,分别是多态、继承、封装,封装的主要目的是隐藏数据。在类式编程语言中,一般都提供
private
,protected
,public
关键词来修饰类的属性与方法,从而决定是否隐藏,但是JavaScript
并没有类的概念,它的封装就是通过立即执行函数来实现的。我们用一个案例来更直观地说明
IIFE
的用途:假设有一个需求,每次调用函数,都返回加1的一个数字(数字初始值为0),下面给出三种实现方式。3.1、 利用全局变量
一般情况下,我们会使用全局变量来保存该数字状态
3.2、 使用函数自定义属性
但上面的方法中,变量
a
实际上只和add
函数相关,却声明为全局变量,不太合适。将变量
a
更改为函数的自定义属性更为恰当函数也是对象,对象可以动态添加属性和方法。
3.3、 使用立即执行函数
上面的方法还是有问题,有些代码可能会无意中将
add.count
重置。使用
IIFE
把计数器变量count
保存为私有变量更安全,同时也可以减少对全局空间的污染需要注意的是这里有一个语法坑:
这是因为第三行没有加分号,浏览器将上面代码解释成如下所示
如果加上分号,就不会出错了
四、带参数的立即执行函数
立即执行函数也是函数,是函数就可以带参数。
把全局作用域下声明的
age
作为匿名函数的参数,匿名函数用变量$
接收。五、立即执行函数的返回值
3.3 就是利用了立即执行函数返回一个函数。