【JavaScript专题】--- 立即执行函数表达式

一 什么是立即执行函数表达式

立即执行函数表达式,其实也可以叫初始化函数表达式,英文名:IIFE,immediately-inovked-function expression。立即执行函数表达式就是在定义的时候就立即执行。

二 立即执行函数表达式的写法

1)写法一

1 (function (a) {
2   console.log('The result is ' + a);
3 })(5);
4 // The result is 5

2)写法二

1 (function (a) {
2   console.log('The result is ' + a);
3 }(5));
4 // The result is 5

三 立即执行函数表达式的特点

1)作用域隔离,避免污染全局的命名空间

通过定义一个匿名函数,创建了一个新的函数作用域,相当于创建了一个“私有”的命名空间,该命名空间的变量和方法,不会破坏污染全局的命名空间。如果想传给外部变量或者方法,通过给window上添加对应属性即可。

例如:Jquery插件就是将window传入,然后给window上添加了$属性。

2)执行完立即销毁

执行完后,内部的局部变量和整个函数会被销毁释放掉。

1 (function add(a, b) {
2   console.log('The result is ' + (a + b));
3   return a + b;
4 }(5, 3));
5 
6 add(4, 6);
7 
8 // The result is 8
9 // Uncaught ReferenceError: add is not defined

3)立即执行函数表达式不需要带函数名

如果带了函数名,则被自动忽略。

四 立即执行函数表达式的错误写法

下边会针对一些立即执行函数表达式的错误写法,深入说明其原因。

要很好的理解下边错误写法的原因,首先要了解:JavaScript中函数的定义方法;JavaScript中表达式。

1)错误写法一

下边的错误写法的原因:浏览器解析器遇到function开头的语句,认为这是一个函数定义,但发现该函数没有函数名,导致报错。

1 function () {
2   console.log('The result is 1');
3 }();
4 
5 // Uncaught SyntaxError: Unexpected token (

说明:为什么给上边示例代码添加一个圆括号,就可以执行并且不报错了?

这是因为添加圆括号后,就变成表达式。

我们都知道定义函数有两种方式:

1 // 函数声明:使用function声明函数,并指定函数名
2 function add() {
3   console.log('The result is 1');
4 }
5 
6 // 函数表达式:使用function声明函数,但未指定函数名,将匿名函数赋予一个变量
7 var add = function() {
8   console.log('The result is 1');
9 };

因此立即执行函数表达式,就类似于给函数表达式方式定义的函数,只是在函数定义完添加了圆括号让该函数立即执行了。

根本的原因还是将一个函数定义,变成了一个表达式。这也是为什么叫立即执行函数表达式的原因。

让一个匿名函数变成一个表达式的方法很多:

1 !function(){}();
2 +function(){}();
3 -function(){}();
4 ~function(){}();
5 new function(){ /* code */ }
6 new function(){ /* code */ }() // 只有传递参数时,才需要最后那个圆括号。
7 ……

2)错误写法二

1 function add() {
2   console.log('The result is ' + a);
3 }();
4 
5 // Uncaught SyntaxError: Unexpected token )

上边代码会被浏览器解析为如下样子:

1 function add() {
2   console.log('The result is ' + a);
3 };
4 ();

第一个分号前是一个完整的函数定义,没有问题;而第二个分号前的(),出现了语法报错。

注意:当我们给后边的那个圆括号中添加一个表达式后,就不会报错了。但注意add函数依然不会执行。

 1 function add() {
 2   console.log('The result is 1');
 3 }(2);
 4 
 5 
 6 // 上边等价于下边代码:一部分是函数声明,一部分是执行表达式。因此函数不会执行。
 7 function add() {
 8   console.log('The result is 1');
 9 };
10 (2);

3)错误写法三

当有多个立即执行函数表达式时,一定要带分号:

1 (function () {
2   console.log('this is IIFE 1');
3 }())
4 (function () {
5   console.log('this is IIFE 1');
6 }())
7 
8 // VM80:4 Uncaught TypeError: (intermediate value)(...) is not a function

说明:不带分号会导致JavaScript执行器认为后边括号内容是前边括号内容的参数,而前边括号最终执行结果并不是一个函数。而下边代码就不会报错:

 1 (function () {
 2   console.log('this is IIFE 1');
 3   return function(a) {
 4     console.log('this is IIFE 1 return');
 5   }
 6 }())
 7 (function () {
 8   console.log('this is IIFE 2');
 9 }())
10 
11 // this is IIFE 1
12 // this is IIFE 2
13 // this is IIFE 1 return

 五 立即执行函数组成的闭包保存状态

 1 // 这个代码是错误的,因为变量i从来就没背locked住
 2 // 相反,当循环执行以后,我们在点击的时候i才获得数值
 3 // 因为这个时候i操真正获得值
 4 // 所以说无论点击那个连接,最终显示的都是I am link #10(如果有10个a元素的话)
 5 
 6 var elems = document.getElementsByTagName('a');
 7 
 8 for (var i = 0; i < elems.length; i++) {
 9 
10     elems[i].addEventListener('click', function (e) {
11         e.preventDefault();
12         alert('I am link #' + i);
13     }, 'false');
14 
15 }
16 
17 // 这个是可以用的,因为他在自执行函数表达式闭包内部
18 // i的值作为locked的索引存在,在循环执行结束以后,尽管最后i的值变成了a元素总数(例如10)
19 // 但闭包内部的lockedInIndex值是没有改变,因为他已经执行完毕了
20 // 所以当点击连接的时候,结果是正确的
21 
22 var elems = document.getElementsByTagName('a');
23 
24 for (var i = 0; i < elems.length; i++) {
25 
26     (function (lockedInIndex) {
27 
28         elems[i].addEventListener('click', function (e) {
29             e.preventDefault();
30             alert('I am link #' + lockedInIndex);
31         }, 'false');
32 
33     })(i);
34 
35 }
36 
37 // 你也可以像下面这样应用,在处理函数那里使用自执行函数表达式
38 // 而不是在addEventListener外部
39 // 但是相对来说,上面的代码更具可读性
40 
41 var elems = document.getElementsByTagName('a');
42 
43 for (var i = 0; i < elems.length; i++) {
44 
45     elems[i].addEventListener('click', (function (lockedInIndex) {
46         return function (e) {
47             e.preventDefault();
48             alert('I am link #' + lockedInIndex);
49         };
50     })(i), 'false');
51 
52 }

 

六 参考资料&内容来源

博客园:https://www.cnblogs.com/tomxu/archive/2011/12/31/2289423.html

SF:https://segmentfault.com/a/1190000003902899

百度:https://baijiahao.baidu.com/s?id=1627496475450434415&wfr=spider&for=pc

博客园:https://www.cnblogs.com/yanzp/p/6371292.html

 

posted on 2019-05-28 11:22  ゛墨メ冰ミ  阅读(343)  评论(0编辑  收藏  举报

导航