一般咱们声明一个函数有如下几种方式:javascript
// 声明函数f1
function f1() {
console.log("f1");
}
// 经过()来调用此函数
f1();
//一个匿名函数的函数表达式,被赋值给变量f2:
var f2 = function() {
console.log("f2");
}
//经过()来调用此函数
f2();
//一个命名为f3的函数的函数表达式(这里的函数名能够随意命名,能够没必要和变量f3重名),被赋值给变量f3:
var f3 = function f3() {
console.log("f3");
}
//经过()来调用此函数
f3();复制代码
若是你看过一些自定义控件的话你会发现他们大多数都是沿用这种写法:html
(function() {复制代码
// 这里开始写功能需求
})(); java
这是咱们常说的当即执行函数(IIFE),顾名思义,也就是说这个函数是当即执行函数体的,不须要你额外去主动的去调用,通常状况下咱们只对匿名函数使用IIFE,这么作有两个目的:
> 一是没必要为函数命名,避免了污染全局变量
> 二是IIFE内部造成了一个单独的做用域,能够封装一些外部没法读取的私有变量。
若是看到这两句话没法理解,那么先从IIFE的运行原理提及。
由于IIFE一般用于匿名函数,这里就用简单的匿名函数做为栗子:
```javascript
var f = function(){
console.log("f");
}
f();复制代码
咱们发现这里f
只是这个匿名函数的一个引用变量,那么既然f()
可以调用这个函数,我把f
替换成函数自己能够么:jquery
function(){
console.log("f");
}();复制代码
运行以后获得以下结果:segmentfault
Uncaught SyntaxError: Unexpected token (复制代码
产生这个错误的缘由是,Javascript引擎看到function关键字以后,认为后面跟的是函数声明语句,不该该以圆括号结尾。解决方法就是让引擎知道,圆括号前面的部分不是函数定义语句,而是一个表达式,能够对此进行运算,这里区分一下函数声明和函数表达式:bash
1、函数声明(即咱们一般使用function x(){}来声明一个函数)
function myFunction () { /* logic here */ }
2、函数表达式(相似以这种的形式)
var myFunction = function () { /* logic here */ };
var myObj = {
myFunction: function () { /* logic here */ }
};复制代码
小学咱们就学过用()
括起来的表达式会先执行,就像下面这样:jquery插件
1+(2+3) //这里先运行小括号里面的内容没有意见撒复制代码
其实在javascript
中小括号也有类似的做用,Javascript引擎看到function关键字会认为是函数声明语句,那么若是Javascript引擎优先看到小括号会怎么样:函数
//用小括号把函数包裹起来
(function(){
console.log("f");
})();复制代码
函数成功执行了:ui
f //控制台输出复制代码
这种状况下Javascript引擎就会认为这是一个表达式,而不是函数声明,固然要让Javascript引擎认为这是一个表达式的方法还有不少:spa
!function(){}();
+function(){}();
-function(){}();
~function(){}();
new function(){ /* code */ }
new function(){ /* code */ }() // 只有传递参数时,才须要最后那个圆括号。
……复制代码
回到前面的问题,为何说IIFE这种形式避免了污染全局变量,若是你见过别人写的jquery插件,里面一般会有相似这样的代码:
(function($){复制代码
//插件实现代码
})(jQuery);`` 这里的
jquery实际上是该匿名函数的参数,联想一下咱们调用匿名函数时候是用
f()那么匿名带参数的就是
f(args)对吧,这里把jquery做为参数传入该函数,那么在函数内部使用形参
$的时候就不会影响到外部环境,由于有些插件也会用到
$`这个限定符,你在这个函数内部能够随意折腾。
以上,在此过程当中参考了如下两篇文章:
javascript当即执行某个函数:插件中function(){}()再思考
JavaScript中的当即执行函数