当前位置: 首页 > 科技观察

深入理解立即执行函数

时间:2023-03-17 12:10:38 科技观察

本文转载自微信公众号《魔法程序员k》,作者魔法程序员k。转载本文请联系大神程序员k公众号。魔术程序员K前言立即执行功能在第三方库中经常用到。它可以用来隔离变量的范围。很多第三方库都会有大量的变量和函数。为了避免ES5环境下的变量污染,开发者想到的解决方案是使用立即执行函数。本文将与大家分享即时执行功能的相关知识点。欢迎有兴趣的开发者阅读本文。概念介绍立即调用匿名函数,也称为立即调用函数表达式(IIFEs),类似于函数声明,但被解释为函数表达式,因为它们被括在括号中。紧跟在第一组括号之后的第二组括号调用前面的函数表达式,并且位于IIFE中的代码在它之外是不可访问的。下面举个例子来说明:(function(){//块级作用域for(vari=0;i<5;i++){console.log(i);}})();console.log(i);解析到console.log(i)时;上面代码中,会报错ReferenceError:iisnotdefined,因为它访问的变量是在IIFE内部定义的,外部无法访问。在es5之前,为了防止变量定义泄露,IIFE是一种非常有效的方式,不会造成闭包相关的内存问题,因为没有引用这个匿名函数。因此,一旦函数执行完毕,它的作用域链就可以被销毁。IIFE的全称是ImmediatelyInvokedFunctionExpression,翻译过来就是立即调用函数表达式。模拟块级作用域使用IIFE来模拟块级作用域,即在函数表达式内部声明变量,然后立即调用函数,这样位于函数体作用域内的变量就像在块级作用域中一样(如上例)。ES6之后,加入了块级作用域的概念,所以如果我们想要达到同样的效果,就不需要再使用IIFE了。我们使用let来重写上面的例子。代码如下:for(leti=0;i<5;i++){console.log(i);}console.log(i);关于变量作用域的更多知识,请看我的另一篇文章:In-深入理解作用域和闭包块一级作用域不能代替直接函数调用的表达。当你的代码运行在不支持ES6+的浏览器上时,你不得不求助于立即调用函数来模拟。实现一个私有变量IIFE可以返回一个函数引用。当这个函数在IIFE的词法作用域之外执行时,也会创建一个闭包,使函数能够访问局部变量。下面举个例子来说明一下,如下:());console.log(getOrderId());console.log(getOrderId());console.log(getOrderId());在上面的代码中:创建了一个自执行函数,它返回一个引用自的函数执行函数内部有一个变量count,它是一个私有变量,外部无法访问。最后返回一个函数引用,形成一个闭包结构。count递增后,与_id拼接,返回到IIFE外无法访问的函数内部。除了从IIFE返回的函数之外,不能在任何地方读取或写入计数变量,因此创建了一个真正私有的状态变量。变量重命名在正常开发中可能会遇到两个不同的库,但是它们暴露的全局变量名是相同的,例如:正在使用Jquery,而另一个库也指定了一个全局变量名为$。为了解决命名冲突的问题,可以将一段代码封装在一个IIFE中,将一个全局变量(如Jquery)作为参数传入IIFE。在函数内部,可以通过任意参数名(如$)访问参数的值,我们举个例子来说明,如下:window.$=functionsomethingElse(){//其他代码};(function($){//其他代码})(jQuery);不管在全局范围内给什么赋值,在IIFE中,这些值都会被屏蔽掉,`参数总是指向Jquery方法。获取全局对象当JavaScript代码在不同的环境中执行时,使用的全局对象是不同的。代码在浏览器环境下运行时,全局对象是window,而在node环境下,全局对象是global。在写一般的js代码时,可以用IIFE来包裹,例如:(function(global){//othercode})(this);包裹后,在IIFE内部使用global时,其值在浏览器环境中显示为window,在node环境中其值为global。IIFE的两种写法立即执行函数的写法有两种:(function(){})()匿名函数包裹在括号运算符中,在匿名函数后面加上括号(function(){}())在括号之后,然后将整个内容包装在括号运算符中。以上两种写法是等价的。如果要立即执行函数,需要注意两点:函数体后面必须有括号。函数体必须是函数表达式,而不是函数。如何声明函数在说两者的区别之前,我们先了解一下js函数的两种声明方式:表达式和声明。函数的声明式写法是:functiontest(){},会导致函数被提升。所有用function关键字声明的变量都会先被解释器编译,无论声明在哪里都可以调用,但它本身不会被执行。test();//测试函数test(){console.log("test");}test();//测试函数的表达式写成:vartest=function(){},这种写法不会导致函数提升必须先声明再调用,否则会报错。test();//错误:TypeError:testisnotafunctionvartest=function(){console.log("test");};两者的区别现在言归正传,函数表达式加()可以直接调用,但是如果把整个声明函数用()包裹起来,就会被编译器认为是函数表达式,所以可以用()直接调用,比如(functiontest(){})()。如果在声明函数后面加上括号,比如functiontest(){},运行后会报错,因为不符合js的语法,如果想让它通过浏览器的语法检查,必须加上符号,如:(),+,!等,如下图:functiontest(){console.log("test");}();//报错SyntaxError:Unexpectedtoken')'+functiontest(){console.log("test");}();//正常执行-functiontest(){console.log("test");}();//正常执行!functiontest(){console.log("test");}();//正常执行~functiontest(){console.log("test");}();//正常执行voidfunctiontest(){console.log("Test");}();//正常执行newfunctiontest(){console.log("test");}();//正常执行和立即执行函数一般写成匿名函数。使用function关键字声明函数,但不要给函数命名。这样声明的函数就是一个匿名函数,比如function(){}。匿名函数不能单独使用,否则会报js语法错误,需要用()包裹起来。当我们需要给匿名函数传值时,可以在后面写上括号,例如:(function(val){console.log(val);}("我是匿名函数的参数"));这里解释的时候,我们会发现上面的代码只是写了第二种立即执行函数的方式??,我们知道函数体后面加了一个小括号,函数就会立即执行。我们知道一个自执行函数需要用()包裹起来。前面我们谈到了用()包裹的代码。编译器会将其识别为函数表达式,因此您可以在其后添加一个()以立即调用它。功能。同时,也可以从这个括号中为匿名函数传递参数,代码如下:(function(val){console.log(val);})("Iamaself-executinganonymousfunction");我们发现上面的代码写的恰好是第一种写函数的方式??写在最后,文章分享。