浅谈立即执行函数

发现一个有意思的问题,有下面一段代码

1
2
3
function f(x, y){
console.log(x + y)
}(3,4)

我们把它输入到firebug下的命令控制台里面,回车之后会输出什么?

两种函数声明方式

在解决这个问题之前我们先看一下js的声明方式:

利用function函数声明(Function Declaration)语句声明函数

1
2
3
4
5
6
//利用function函数声明语句声明函数,利用此函数声明函数,函数会在所有程序执行之前进行声明,
//也就是说我们可以在function a 这条语句之前调用这个函数
a()
function a() {
console.log("a函数声明")
}

使用函数表达式(Function Expression)来声明函数

1
2
3
4
5
6
7
8
9
10
//使用函数表达式来声明一个匿名函数,编译器会先声明一个变量b,
//然后在执行到这个语句的时候,再对=右边的匿名函数进行声明,再把b指向匿名函数
var b = function() {
console.log("b函数声明")
}
//使用函数表达式来声明函数,同匿名函数,只不过我们的函数有名字,也就是说c和d指向同一个函数,我们用c或d都可以
//调用这个函数,但是需要注意的是,在执行这条语句之前c的数值是undefine,而d则是未定义(万恶的IE8有[BUG](https://www.jb51.net/onlineread/named-function-expressions-demystified/)),在这条语句执行后c指向函数d,而d在全局是undefined 因为,其只在函数内部可见,在外部不可见
var c = function d() {
console.log("c函数声明")
}

要区分一个代码是函数声明还是函数表达式,那要看代码的应用上下文。

  • 如果有运算符号,那它就是函数表达式。
  • 如果没有运算符号而且不在条件判断语句中,就说明是函数声明,无法直接加()进行调用(运算符包括赋值号跟括号)
  • 如果在条件语句中,函数声明也会强行被当做函数表达式执行。

注意我们如果需要向下面这样声明函数,会在不同浏览器下得到不同结果
undefined

我们应该是用函数表达式声明,就可以的得到对的结果

立即执行函数(Immediately Invoked Function Expression)

在我们使用函数表达式来声明函数的时候,b指向的就是函数,我们要执行函数的时候就是b()。那么b的内容是什么 ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
我们把b的内容打印出来b == function() {
console.log("b函数声明")
}
我们是不是想到了,如果 function() {
console.log("b函数声明")
}()
是不是也可以让函数得到执行,我们把这种执行叫做立即执行函数,不过此处有个坑。
他会报错`token(`,因为function是个关键字,编译器在编译的时候,如果以function开头那么
就应该以}结尾,但是咱么以)结尾了,所以我们只需要不让function开头就好啦,我们可以
给function前面放!/+/-或者用一个()把function() {
console.log("b函数声明")
}()
整个包起来,或者只包裹函数声明的那一部分,不过用!/+ /-有可能改变函数的返回值,同时为了更
符合函数的定义所以我们一般用()把函数声明的那一部分包起来,就变成了
{% codeblock lang:Javascript %}
(function f(){
console.log("xxx")
})()
{% endcodeblock %}

我们需要注意的是,小括号有多种语义,此时的语义是:强制表达式运算 ,被称作:分组操作符
他只能包含表达式,所以此时的小括号就把语句转成了函数表达式的声明方式,但是,我们如果把return,var等语句写进去就会报语法错误


有关立即执行函数以及闭包等,等以后知识库充足了再写
IIFE(Immediately Invoked Function Expression),立即执行函数表达式
javascript中没用私有作用域的概念,如果在多人开发的项目上,你在全局或局部作用域中声明了一些变量,可能会被其他人不小心用同名的变量给覆盖掉,

根据javascript函数作用域链的特性,可以使用这种技术可以模仿一个私有作用域,用匿名函数作为一个“容器”,“容器”内部可以访问外部的变量,

而外部环境不能访问“容器”内部的变量,所以( function(){…} )()内部定义的变量不会和外部的变量发生冲突,俗称“匿名包裹器”或“命名空间”。

感觉不错的话给博主赞助一下呗