小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
前言
函数,无人不知,无人不晓得。 有一些基础的概念是必须知道的,今天一起学习IIFE吧。
定义
IIFE( 立即调用函数表达式)是一个在定义时就会立即执行的 JavaScript 函数。
最常见的形式:
;(function () {
statements
})();
当然,在文件的开头加一个;绝对不是坏事,现代化的代码合并工具是很智能的,ES6也是允许一行有效的代码之后不添加;, 但是也是与例外的。
下面的代码是执行会报错
var arr = []
[1,2,3].map(v=>v*v)
// Uncaught TypeError: Cannot read properties of undefined (reading 'map')
添加一个;号,就没问题了
var arr = [];
[1,2,3].map(v=>v*v)
// (3) [1, 4, 9]
至于是为什么,嘻嘻,先保密!
IIFE的作用
避免污染全局作用域
避免了外界访问此 IIFE 中的变量,而且又不会污染全局作用域。
比如浏览器环境下:
var a = 10;
// 如果是浏览器
console.log(window.a); // 10
console.log(a); // 10
a挂到了window下面,成为了全局的变量,这就是全局污染。
如果这样到处乱申明,很可能覆盖其他的变量,是很危险的, 大名鼎鼎的jQuery因此还搞了专门处理名称冲突的方法。
var jq=$.noConflict();
减少内存占用
IIFE执行完毕后,不被引用的变量是会被回收的,可以减少不必要的内存占用。
比如我们就打印一下浏览器的userAgen信息
// 非IIFE
function printUserAgent(){
console.log(navigator.userAgent);
}
printUserAgent();
console.log(typeof printUserAgent); // function
// IIFE
;(function (){
function printUserAgent(){
console.log(navigator.userAgent);
}
printUserAgent();
})()
console.log(typeof printUserAgent); // undefined
非IIFE部分的代码,执行完毕后,printUserAgent依旧存在,而IIFE的执行了回收。
形成块作用域
经典的题目, 就是用IIFE + 闭包形成私有作用域。
// 非IIFE
for (var i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
// 5 5 5 5 5
for (var i = 0; i < 5; i++) {
(function (v) {
setTimeout(function () { console.log(v) }, 1000)
})(i);
}
// 0 1 2 3 4
带返回值
最后直接return 就行
var utils = (function (){
return {
get now(){
return Date.now();
}
}
})();
console.log(utils.now); // 1633438917346
初始化参数
var utils = (function (global){
return {
get now(){
return Date.now();
},
getGlobal(){
return global
}
}
})(window);
console.log("global:", utils.getGlobal());
// Window {window: Window, self: Window, document: document, name: '', location: Location, …}
其他IIFE形式
其实有很多形式的IIFE, 基本任何求值得均可以达到目标,当然,可能有些不能有效的传递参数。
+ function log (){
console.log("1111");
}() // 1111
是不是很有意思,其他的-,~, !,void等等符号均可形成IIFE。
有趣的求值符号
看点有意思的:
function log (){
console.log("1111");
}()
// Uncaught SyntaxError: Unexpected token ')'
function log (){
console.log("1111");
}(
// Uncaught SyntaxError: Unexpected end of input
function log (){
console.log("1111");
}(1)
// 1
;()
// Uncaught SyntaxError: Unexpected token ')'
可以看出来,前面没有求值符号的时候, 引擎的解析,对函数解析完毕后,以(开始,作为新解析的开始。
但是有求值符号后,等同于如下:
+ (function log (){
console.log("1111");
}())
是不是有些意思。
更进一步的解读,用得用AST看看了。
小结
今天你收获了吗?