zoukankan      html  css  js  c++  java
  • 【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

  • 相关阅读:
    Java多线程学习(二)synchronized关键字(2)
    Java多线程学习(二)synchronized关键字(2)
    如何自己动手获取大量知乎网民数据?
    如何自己动手获取大量知乎网民数据?
    Java多线程学习(二)synchronized关键字(1)
    Java多线程学习(二)synchronized关键字(1)
    Java多线程学习(一)Java多线程入门
    集合框架源码学习之HashMap(JDK1.8)
    集合框架源码学习之LinkedList
    ubuntu下安裝程序的三個方式
  • 原文地址:https://www.cnblogs.com/zhaoweikai/p/10936101.html
Copyright © 2011-2022 走看看