最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 深入理解立即执行函数

    正文概述 掘金(神奇的程序员)   2021-04-21   560

    前言

    立即执行函数常用于第三方库,它可以用来隔离变量作用域,很多第三方库都会存在大量的变量和函数,在ES5环境下为了避免变量污染,开发者想到的解决办法就是使用立即执行函数。

    本文就跟大家分享下立即执行函数的相关知识点,欢迎各位感兴趣的开发者阅读本文。

    概念介绍

    立即调用的匿名函数又被称作立即调用的函数表达式(IIFE),它类似于函数声明,但由于被包含在括号中,所以会被解释为函数表达式。紧跟在第一组括号后面的第二组括号会立即调用前面的函数表达式,位于IIFE中的代码在其外部是无法访问的。

    我们举个例子来说明下:

    (function() {
      // 块级作用域
      for (var i = 0; i < 5; i++) {
        console.log(i);
      }
    })();
    console.log(i);
    
    

    上述代码中当解析到console.log(i);时,会报错ReferenceError: i is not defined,这是因为它访问的变量是在IIFE内部定义的,在外部访问不到。

    在es5以前,为了防止变量定义外泄,IIFE是个非常有效的方式,这样也不会导致闭包相关的内存问题,因为不存在对这个匿名函数的引用。因此,只要函数执行完毕,其作用域链就可以被销毁。

    模拟块级作用域

    使用IIFE可以模拟块级作用域,即在一个函数表达式内部声明变量,然后立即调用这个函数,这样位于函数体作用域的变量就像是在块级作用域中一样(如上述例子所示)。

    在ES6以后,新增了块级作用域的概念,因此我们想实现同样的效果,就无需再使用IIFE了,我们用let来重写下上面的例子,代码如下所示:

    for (let i = 0; i < 5; i++) {
      console.log(i);
    }
    console.log(i);
    
    

    有关变量作用域的更多知识点请移步我的另一篇文章:深入理解作用域和闭包

    实现私有变量

    IIFE可以返回一个函数引用,当这个函数在IIFE的词法范围外执行,也会创建一个闭包,使函数能够访问局部变量。

    我们举个例子来说明下,如下所示:

    const getOrderId = (function() {
      let count = 0;
      return function() {
        ++count;
        return `id_${count}`;
      };
    })();
    console.log(getOrderId());
    console.log(getOrderId());
    console.log(getOrderId());
    console.log(getOrderId());
    

    上述代码中:

    • 创建了一个自执行函数,其返回一个函数引用
    • 自执行函数内部有一个变量count,它就是一个私有变量,外部无法访问
    • 最后,返回一个函数引用,形成闭包结构,对count自增后与_id进行拼接并返回

    在IIFE之外无法访问函数内部的count变量,除了从IIFE中返回的函数,别处无法读写该变量,这样就能创建真正的私有状态变量。

    变量重命名

    在平常开发中可能遇到两个不同的库,他们暴露的全局变量名却是相同的,例如:正在使用Jquery,另一个库也指定了一个名为$的全局变量。

    为了解决命名冲突问题,可以将一段代码封装在一个IIFE中,将一个全局变量(比如Jquery)作为参数传入IIFE,在函数内部,就可以以一个任意的参数名(比如 $)来访问该参数值,我们举个例子来说明下,如下所示:

    window.$ = function somethingElse() {
    
        // 其他代码
    
    };
    
     
    
    (function($) {
    
        // 其他代码
    
    })(jQuery);
    

    捕获全局对象

    JavaScript代码在不同环境执行时,所使用的全局对象是不同的,当代码在浏览器环境运行时,全局对象是window,但是在node环境下,全局对象则是global。

    在写通用js代码时,就可以利用IIFE将其包装起来,例如:

    (function(global) {
    
        // 其他代码
    
    })(this);
    

    包装之后,在IIFE内部使用global时在浏览器环境下其值就是window,node环境下其值就是global。

    IIFE的两种写法

    立即执行函数有两种写法:

    • (function(){})() 匿名函数包裹在一个括号运算符中,后面再跟一个小括号
    • (function(){}()) 匿名函数后面跟一个小括号,然后整个包裹在一个括号运算符中

    上述两种写法是等价的,要想立即执行函数做到立即执行,要注意两点:

    • 函数体后面要有小括号
    • 函数体必须是函数表达式而不能是函数声明

    函数的声明方式

    在讲它们两者之间的区别之前,我们先来了解下js函数的两种声明方式:表达式和声明式。

    函数的声明式写法为:function test(){},这种写法会导致函数提升,所有通过function关键字声明的变量都会被解释器优先编译,不管声明在什么位置都可以调用它,但是它本身并不会被执行。

    
    test(); // 测试
    function test() {
      console.log("测试");
    }
    test(); // 测试
    

    函数的表达式写法为:var test = function(){},这种写法不会导致函数提升,必须先声明后调用,不然就会报错。

    test(); // 报错:TypeError: test is not a function
    var test = function() {
      console.log("测试");
    };
    

    二者的区别

    现在,我们回到正题,函数表达式加上()可以被直接调用,但是把整个声明式函数用()包起来的话,则会被编译器认为是函数表达式,从而可以用()来直接调用,如(function test(){})()

    如果将括号加在声明式函数后面如function test(){},运行之后会报错,因为不符合js的语法,想让其通过浏览器的语法检查,就必须添加符号,比如:()、+、!等,如下所示:

    function test(){
      console.log("测试");
    }(); // 报错 SyntaxError: Unexpected token ')'
    
    +function test() {
      console.log("测试");
    }(); // 正常执行
    
    -function test() {
      console.log("测试");
    }(); // 正常执行
    
    !function test() {
      console.log("测试");
    }();  // 正常执行
    
    ~function test() {
      console.log("测试");
    }();  // 正常执行
    
    void function test() {
      console.log("测试");
    }();  // 正常执行
    
    new function test() {
      console.log("测试");
    }();  // 正常执行
    

    立即执行函数一般也写成匿名函数,使用function关键字声明一个函数,但未给函数命名,通过这种方式声明的函数就是匿名函数,例如function(){}

    匿名函数不能单独使用,否则会js语法报错,需要用()包起来,当我们需要给匿名函数传值时,写在其后面的括号即可,例如:

    (function(val) {
      console.log(val);
    }("我是匿名函数的参数"));
    
    

    我们知道自执行函数是需要用()将其包裹起来的,前面我们讲到用()包裹起来的代码,编译器会认定它为函数表达式,因此可以在其后面加个()立即调用这个函数。同时也可以从这个括号来为匿名函数传参,代码如下所示:

    (function(val) {
      console.log(val);
    })("我是自执行匿名函数");
    

    代码地址

    本文为《JS原理学习》系列的第6篇文章,本系列的完整路线请移步:《JS原理学习 (1) 》学习路线规划

    本系列文章的所有示例代码,请移步:js-learning

    写在最后

    至此,文章就分享完毕了。

    我是神奇的程序员,一位前端开发工程师。

    如果你对我感兴趣,请移步我的个人网站,进一步了解。

    • 文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注?
    • 本文首发于掘金,未经许可禁止转载?

    起源地下载网 » 深入理解立即执行函数

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元