浅析立即执行函数
一、是什么
立即执行函数又名[[IIFE]],具体对于它的介绍可以看我之前的文章。
和它相对应的是[[具名函数表达式]],是相对的。先来看看具名函数表达式:
function foo() {
console.log('橘子哥')
}
而IIFE的典型例子如下:
;(function() {
console.log('橘子哥')
}())
有三个不同:
- [[IIFE]]没有函数名,具名函数有,可以通过console.log(
foo.name
)打印出来 - [[IIFE]]直接调用,这就是它立即的由来,而具名需要添加
foo()
才能够运行 - [[IIFE]]第一个字符是
;
二、IIFE给出我们带来了什么
- 戳破了形成[[闭包]]需要函数嵌套的谣言
创建一个独立的作用域,让我知道函数嵌套函数的目的是什么,详见上一篇文章
- 解决了循环打印的问题
经典面试题:
for(var i = 0; i < 5; i++) {
setTimout(function(){
console.log(i) // 为啥打印出来额都是5呀,而不是0 ,1 ,2 ,3, 4
})
}
或者
var lis = ul.querySelector('li')
for(var i = 0; i < 6; i++) {
lis[i].onclick = function() {
console.log(i) // 为啥打印出来额都是5呀,而不是0 ,1 ,2 ,3, 4
}
}
两个例子都是一个问题。i相对于函数是全局变量,所以不管循环多少个函数,里面的i
指向的都是同一个内存,而这个内存中放的值只有一个。所以它们打印出来的值自然都是一样的。
要解决这个问题,自然就是让这些函数能够执行不同的i
。所以函数作用域就能够办到这件事情。
for(var i = 0; i < 5; i++) {
!function foo(j) {
setTimout(function(){
console.log(j) // 为啥打印出来额都是5呀,而不是0 ,1 ,2 ,3, 4
})
}(j)
}
var lis = ul.querySelector('li')
for(var i = 0; i < 6; i++) {
!function foo(j) {
lis[j].onclick = function() {
console.log(j) // 为啥打印出来额都是5呀,而不是0 ,1 ,2 ,3, 4
}
}(j)
}
ES6之前JS原生又不提供块级作用域,所以只能用[[函数作用域]]模拟了。现在处理这样的问题,[[let]]显然是更加方便的。
总结一下:
-
改变变量的作用域(创建一个独立的作用域)
-
封装临时变量。
三、一些少为人知的技巧
写上函数名, 两个作用:
第一个,辅助定位BUG。有小面这串代码:
!function(){
a
console.log(11)
}()
明显看出其中a没有定义,会在控制台把如下错误。
如果我们给它添加上函数名,会有什么不一样的么?
!function foo() {
a
console.log(11)
}()
报错信息就会出现foo
函数名。这就是为啥说它可以辅助定位BUG。
第二个,老一代框架写法, 比如说JQ:
;(function JQ(g){
g(window)
}(function g(window){
// code
}))
了解一下即可。
转载自:https://juejin.cn/post/7197424168622473271