JavaScript中的函数作用域的存在就是为了把变量和函数“隐藏”起来
符合我们的最小特权原则
同时它的另一个好处是可以避免同名标识符的冲突
今天主要来谈谈这个立即执行函数
在此之前的复习一下匿名函数与具名函数
无论是匿名还是具名,都是针对函数表达式来说的
函数声明那就必须得有名字了,否则会报错的
function foo(){ //函数声明 //...}
这里我解释一个彩蛋,可能大家看我写文章的时候示例代码总是喜欢用一些
fn、func、demo、foo、bar、foobar之类的词
fn、func就是function“函数”的缩写
demo就是单词demonstration“示例”的缩写
foo、bar、foobar我们经常能够在技术书籍还有计算机文献中看到
foo是fu的变体,fuck-up缩写,意思是“一团糟”
bar是“beyond all recognition”,意思是“超越认知”,通俗说“识别不了,一塌糊涂”
就是一些占位词,相当于我们的小明小红、甲乙丙丁、张三李四…
函数表达式是可以有名字,也可以没有名字的
var foo = function(){...}; console.log(foo.name); //foo var bar = function foobar(){...};//不要这么写 console.log(bar.name); //foobar
可以看到第二种写法只是单纯地改变了函数的name属性
除此之外百无一用,我们不要这么写
除此之外我们最常见的用法就是函数表达式作为回调参数了
比如说在定时器中
setTimeout(function(){ //...},1000);
这里我写了匿名函数表达式
它用起来简单粗暴
但有几个缺点
追踪栈中没函数名,调试困难
如果需要引用自身,只能用arguments.callee(ES5严格模式禁用)
降低了函数可读性、可理解性
我们在解除事件绑定时,也需要函数名(如果不是用onclick等等直接绑定的话)
所以
给函数表达式一个名字是一个最佳实践,是一个好习惯
setTimeout(function timerHandler(){ //...},1000);
立即执行函数,我习惯这么叫
也有叫自执行函数、自动执行函数什么的
说的更标准一些
立即执行函数表达式
注意我的用词,是函数表达式
它并不是什么语法
而是大家用着用着发现还能这么用
于是就流传开来,直到现在
顾名思义,就是执行流运行到这个函数就立刻执行了
社区给它规定了术语:IIFE(Immediately Invoked Function Expression)
我们常用的用法是:
(function(){ //...}());
(function(){ //...})();
我们用IIFE的时候一般都是使用一个匿名函数表达式
当然你加上名字也不错,同时拥有了具名函数表达式的优点
两种用法完全等价,使用哪种由你决定
但我更愿意把括号写在外面,感觉看着比较舒服
而且看到很多大神也和我一样
稍微进阶的用法就是在立即执行函数中传递参数
比如说我们常见的传递window
var a = '全局'; (function IIFE(global){ var a = '局部'; console.log(a);// "局部" console.log(global.a);// "全局"})(window);
传window有什么好处呢?
从我们作用域的角度分析
(可以看看我写的作用域->传送门)
全局对象的引用缓存到了局部环境
这样我们可以更快的访问到全局对象,不用再跳到顶级作用域查找
这点小优化不是重点
重点的压缩代码的时候可以进行优化
也许上面的代码压缩工具可以压缩成这样
var a = '全局'; (function IIFE(g){ var a = '局部'; console.log(a);// "局部" console.log(g.a);// "全局"})(window);
当代码非常大的时候,可不要小看这优化
IIFE还有一种变式,你一定见过
(function IIFE(demo){ demo(window);})(function demo(global){ //... });
这种把要运行的函数放进参数的模式看起来很麻烦
但却被广泛使用,jQuery等框架整体架构也和这个很像
如果看习惯了,就会感觉它比我们传统的使用方法更容易理解
整体的函数表达式定义在IIFE第二部分,作为参数传递进IIFE第一部分
然后调用了这个函数,并且把window作为参数传入
立即执行函数为什么能够自动执行?
(function(){ //...})();
为什么function(){}()
这样写不可以
因为这是函数声明,函数声明是不可以执行的
只有表达式才能够执行
var demo = function(){ console.log(1);// 1 return 123; }(); console.log(demo);// 123
这就是一个表达式,所以可以被执行
demo得到的是函数的返回值
既然表达式可以被执行,那么以下方式都可以被立即执行
+function(){ console.log(1);// 1}(); -function(){ console.log(2);// 2}(); !function(){ console.log(3);// 3}() ,function(){ console.log(4);// 4}();
可以看出甚至是逗号,都可以它们变成函数表达式,然后立刻执行
不过我们千万不要这么写
如果函数有返回值的话,可能会产生意想不到的副作用
并且可读性也不好
函数声明必须有名字
具名函数表达式是一个最佳实践
立即执行函数表达式用法:(function(){}());
(function(){})();
立即执行函数传递window参数优化在作用域链查找window速度,有利于压缩代码
只有表达式才能够被执行
以上就是JavaScript匿名、具名函数与立即执行函数IIFE详解 的内容,更多相关内容请关注PHP中文网(www.php.cn)!