Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
本题难度:⭐ ⭐
答:立即执行函数可以立即执行一段代码逻辑,一般一些独立的代码逻辑都会封装成一个函数,如果不想先封装,再调用,不想起函数名,就可以使用立即执行函数来写。
立即执行函数的写法
有很多稀奇古怪的写法,这里只罗列四种,其实一般用的都是前两种:
// 第一种,用一个括号把自执行函数整体包起来
;(function sayName () {
console.log('阿林')
}())
// 第二种,和第一种是类似的,这种写法用得比较多
;(function sayName () {
console.log('阿林')
})()
// 第三种,函数表达式立即执行
const sayName = function(){
console.log('阿林')
}()
// 第四种,函数表达式作为一元操作符的参数立即调用
!function(){
console.log('阿林')
}()
+function(){
console.log('阿林')
}()
-function(){
console.log('阿林')
}()
~function(){
console.log('阿林')
}()
第四种方式会和函数返回值进行运算,且代码不易懂,不推荐使用。
你可能注意到了立即执行函数前面加了个 ;,为啥要这么写呢?
a = b + c
;(function() { // 故意将分号放在这里,防止语句被理解为对函数c的调用
// 代码
})();
立即执行函数的一些用途
立即执行一些代码逻辑
一般一些独立的代码逻辑都会封装成一个函数,如果不想先封装,再调用,不想起函数名,就可以使用立即执行函数来写。
比如:
兼容 ie 浏览器
这种系统只需要判断一次的逻辑,不需要复用,就可以用自执行函数来写
;(function () {
var userAgent = navigator.userAgent //取得浏览器的userAgent字符串
var isIe =
(userAgent.indexOf('compatible') > -1 &&
userAgent.indexOf('MSIE') > -1) ||
(userAgent.indexOf('Trident') > -1 &&
userAgent.indexOf('rv:11.0') > -1)
if (isIe) {
window.location.href = 'IEBack.html'
}
})()
给系统注入一些三方功能模块
比如,阿里的性能监控系统 arms 给出的引用示例代码, 就是用的立即执行函数。
!(function (c, b, d, a) {
c[a] || (c[a] = {})
c[a].config = {
pid: 'xxx',
appType: 'web',
imgUrl: 'https://arms-retcode.aliyuncs.com/r.png?',
sendResource: true,
enableLinkTrace: true,
behavior: true,
enableSPA: true
}
with (b)
with (body)
with (insertBefore(createElement('script'), firstChild))
setAttribute('crossorigin', '', (src = d))
})(window, document, 'https://retcode.alicdn.com/retcode/bl.js', '__bl')
模拟块级作用域,创建函数的私有变量
其实这是闭包的功能,但是可以用立即执行函数少写一点代码。
ES6 之前,JS 没有块级作用域,要想把某些变量隔离,可以使用闭包来实现。
var fn = function () {
var i = 0
return { // fn 函数返回一个对象,有 get、set 等方法,来操作私有变量 i
get: function () {
return i
},
set: function (val) {
i = val
},
increment: function () {
return ++i
}
}
}
const counter = fn() // 这里执行 fn 函数,拿到 counter 对象
counter.get() // 0
counter.set(3)
counter.increment() // 4
counter.increment() // 5
如果我们试图从全局作用域直接访问 counter.i ,会得到 undefined,因为 i 是定义在函数 fn 作用域内的变量,它并不是 counter的属性。同样的,如果我们试图访问 i 也会收到错误,因为 i 并没有在全局作用域中定义。
既然这个函数 fn 不是为了复用,只是为了在自己作用域里创建一些私有变量,就只执行一次就好了,不需要专门封装,也不需要特别地给他起一个函数名,就用立即执行函数就行。
var counter = (function () {
var i = 0
return {
get: function () {
return i
},
set: function (val) {
i = val
},
increment: function () {
return ++i
}
}
})()
counter.get() // 0
counter.set(3)
counter.increment() // 4
counter.increment() // 5
网络上很多文章把立即执行函数和闭包混淆在一起,从上面的例子可以看出,不使用立即执行函数,也能实现闭包的功能。
所以说,模拟块级作用域,创建函数的私有变量这个是闭包的使用场景,和立即执行函数半毛钱关系没有,立即执行函数做的事情就是让函数可以立即执行,让代码少写一点而已。
结尾
如果我的文章对你有帮助,你的👍就是对我的最大支持^_^
我是阿林,输出洞见技术,再会!
上一篇:
「前端每日一问(21)」说一下 var、let 和 const 的区别
下一篇: