一、什么是立即执行函数
顾名思义,声明一个函数并马上调用这个函数就叫做立即执行函数;也可以说立即执行函数是一种语法,让你的函数在定义以后立即执行;立即执行函数又叫做自执行函数。
二、立即执行函数的写法
立即执行函数的写法有三种:
( function ( “ 参数 ” ) { " 函数方法 " ; } ) ( “ 给参数传的值 ” )
( function ( " 参数 " ) { “ 函数方法 ” ; } ( " 给参数传的值 " ) )
! function ( " 参数 " ) { " 函数方法 " ; } ( " 给参数传的值 " )
// ! 可以换作 void 或其他运算符(比如 +,-,= 等,都能起到立即执行的作用)
立即执行函数是很自私的,它的内部可以访问全局变量。但是除了它自身内部,外部是无法访问它的。
function aaa(a,b){
return sum = a + b;
}
(function bbb(a,b){
return sum = a + b;
}(1, 2))
console.log(aaa)
console.log(bbb)
上面代码中,是一个普通函数与一个立即执行函数,输出这两个函数会发现:普通函数aaa被全部打印出来,而打印立即执行函数bbb却报错。返回结果:
立即执行函数相当于一个瓶口朝下的杯子,当定义它的时候,它会倾斜,把杯口露出来,吸收外面的新鲜空气;当它执行完毕,杯口不再外露,紧闭起来,与外界再无关联。
三、使用立即执行函数的好处
通过定义一个匿名函数,创建了一个新的函数作用域,相当于创建了一个“私有”的命名空间,该命名空间的变量和方法,不会破坏污染全局的命名空间。此时若是想访问全局对象,将全局对象以参数形式传进去即可,如jQuery代码结构:
(function (window) {
// jquery code
})(window);
其中window即是全局对象。作用域隔离非常重要,是一个JS框架必须支持的功能,jQuery被应用在成千上万的JavaScript程序中,必须确保jQuery创建的变量不能和导入他的程序所使用的变量发生冲突。
四、注意点
前面介绍了3种立即执行函数的写法,使用前两种写法的立即执行函数,它们的前一个函数必须要有分号。
举个栗子:
(function (a){
console.log(a)
})(1)
(function (a){
console.log(a)
}(2))
ECMAScript规范具有分号自动插入规则,但是在上面代码中,在第一个立即执行函数末尾却不会插入“;”,因此上面代码会被解释为如下形式:
(function (a){
console.log(a)
})(1)(function (a){
console.log(a)
}(2));
此时浏览器报错:
因此,立即执行函数前的一个函数必须要有分号,保险起见,可以直接在立即执行函数的前面添加“;”
;(function (a){
console.log(a)
})(1);
(function (a){
console.log(a)
}(2));
五、扩展一道经典的面试题
非匿名自执行函数,函数名只读
看看下面代码输出什么?
var b = 10;
(function b(){
b = 20
console.log(window.b)
console.log(b)
})()
输出:
再扩展一下:
var b = 10;
(function b(){
console.log(b)
b = 5
console.log(window.b)
var b = 20
console.log(b)
})()
输出:
上面代码中,第一个值undefined,是因为下面有 var b = 20,var声明会提升到function最开头,但赋值发生在最后,function里面的代码等价于:
var b
console.log(b)
b = 5
console.log(window.b)
b = 20
console.log(b)
END