立即执行函数 用法理解

一、函数命名的几种方式:

1、函数的声明式写法:function foo(){/*...*/},这种写法会导致函数提升,所有function关键字都会被解释器优先编译,不管是声明在什么位置,都可以调用它,但是它本身不会被执行,定义只是让解释器知道其存在,只有在被调用的时候才会执行。

例:立即执行函数 用法理解立即执行函数 用法理解

 这里的foo(a,b)函数会被 Javascript引擎优先编译,因此在进行函数调用时候  不论放在哪个位置都可以成功打印出 结果。

2、函数的表达式写法为:var foo=function(){/*...*/},这种写法不会导致函数提升,于是就必须先声明,再调用,否则会出错,如图2。

 例:立即执行函数 用法理解立即执行函数 用法理解

 

 

  这里的函数表达式必须等到Javascirtp引擎执行到它所在行时,才会从上而下一行一行地解析函数表达式。因此在未声明之前调用,则报错。

 引:匿名函数:function(){/*...*/};,使用function关键字声明一个函数,但未给函数命名,因此叫做匿名函数。匿名函数属于函数表达式,匿名函数有很多作用,赋予一个变量则创建函数,赋予一个事件则成为事件处理程序或创建闭包等等。

如果将匿名函数赋予一个变量,就叫做上述的函数表达式了。

总结:函数声明式写法和函数表达式写法有两个区别:一个是函数提升的区别,另一个是:函数表达式可以在其后面加上() 立即调用该函数,函数声明只能通过foo()方式调用,后面加括号会报错,不符合语法规范。
例:

立即执行函数 用法理解立即执行函数 用法理解

 

 

 如果想通过语法检查,可以在函数声明式写法中加些符号,如:()、+、!等。

例:

function foo(){console.log("Hello World!")}()     //声明函数后加()会报错
(function foo(){console.log("Hello World!")}())   //用括号把整个表达式包起来,正常执行 (function foo(){console.log("Hello World!")})()   //用括号把函数包起来,正常执行 !function foo(){console.log("Hello World!")}()    //使用!,求反,这里只想通过语法检查。 +function foo(){console.log("Hello World!")}()    //使用+,正常执行 -function foo(){console.log("Hello World!")}()    //使用-,正常执行 ~function foo(){console.log("Hello World!")}()   //使用~,正常执行 void function foo(){console.log("Hello World!")}()  //使用void,正常执行 new function foo(){console.log("Hello World!")}()  //使用new,正常执行

从上述代码可以看出,在function前面加!、+、 -甚至是逗号等到都可以起到函数定义后立即执行的效果,而()、!、+、-、~等运算符,都可以将函数声明转换成函数表达式,消除了javascript引擎识别函数表达式和函数声明的歧义,告诉javascript引擎这是一个函数表达式,不是函数声明,可以在后面加括号,并立即执行函数的代码。PS:加括号是最安全的做法,因为!、+、-等运算符还会和函数的返回值进行运算,有时会造成不必要的麻烦。

 

二、立即执行函数。

1、写法:( function() {/*...*/})()( function() {/*...*/}() )

一般也写成匿名函数:匿名函数写法为function(){/*...*/},就是使用function关键字声明一个函数,但未给函数命名,倘若需要传值,直接将参数写到括号内即可,具体示例如下所示。

 立即执行函数 用法理解

 

 

 将它赋予一个变量则创建函数表达式,赋予一个事件则成为事件处理程序等。但是需要注意的是匿名函数不能单独使用,否则会js语法报错,至少要用()包裹起来。

立即执行函数 用法理解

 

 

 上面的例子可以写成如下形式:

(function(){console.log("我是匿名函数。")}())
(function(){console.log("我是匿名函数。")})()
!function(){console.log("我是匿名函数。")}()
+function(){console.log("我是匿名函数。")}()
-function(){console.log("我是匿名函数。")}()
~function(){console.log("我是匿名函数。")}()
void function(){console.log("我是匿名函数。")}()
new function(){console.log("我是匿名函数。")}()

2、作用

  立即执行函数的作用是:1.创建一个独立的作用域,这个作用域里面的变量,外面访问不到,这样就可以避免变量污染。2.闭包和私有数据。

  javascript中没用私有作用域的概念,如果在多人开发的项目上,你在全局或局部作用域中声明了一些变量,可能会被其他人不小心用同名的变量给覆盖掉,根据javascript函数作用域链的特性,可以使用这种技术可以模仿一个私有作用域,用匿名函数作为一个“容器”,“容器”内部可以访问外部的变量,而外部环境不能访问“容器”内部的变量,所以( function() {/*...*/})()内部定义的变量不会和外部的变量发生冲突,俗称“匿名包裹器”或“命名空间”。

 

引申:

  闭包问题:

<ul id=”test”>
    <li>这是第一条</li>
    <li>这是第二条</li>
    <li>这是第三条</li>
</ul>

<script>
    var liList=document.getElementsByTagName(‘li‘);
    for(var i=0;i<liList.length;i++)
    {
        liList[i].onclick=function(){
            console.log(i);
        }
    };
</script>

  很多人觉得这样的执行效果是点击第一个li,则会输出1,点击第二个li,则会输出2,以此类推。但是真正的执行效果是,不管点击第几个li,都会输出3。因为 i 是贯穿整个作用域的,而不是给每个 li 分配了一个 i,用户触发的onclick事件之前,for循环已经执行结束了,而for循环执行完的时候i=3。

 

  1》但是如果我们用了立即执行函数给每个 li 创造一个独立作用域,就可以改写为下面的这样,这样就能实现点击第几条就能输出几的功能。

<script>
    var liList=document.getElementsByTagName(‘li‘);
    for(var i=0;i<liList.length;i++)
    {
        (function(ii) {
           liList[ii].onclick=function(){
               console.log(ii);
           }
       })(i)
    };
</script>

  在立即执行函数执行的时候,i 的值被赋值给 ii,此后 ii 的值一直不变。i 的值从 0 变化到 3,对应3 个立即执行函数,这 3个立即执行函数里面的 ii 「分别」是 0、1、2。即:点击第几个li,就输出几

  2》当然使用ES6语法中的let也可以实现上述的功能,将for循环中的var换成let去声明,如下所示

<script>
     var liList=document.getElementsByTagName(‘li‘);
     for(let i=0;i<liList.length;i++)
     {
            liList[i].onclick=function(){
                console.log(i);
             }
     }
</script>

 

立即执行函数 用法理解

 

立即执行函数 用法理解

上一篇:「CodeForces」847A Union of Doubly Linked Lists


下一篇:jenkins pipeline构建后返回构建结果给gitlab