什么是 IIFE
What is an IIFE
一句话:立即执行函数表达式 (Immediately Invoked Function Expression)—— 定义完马上调用,用来造一个隔离的作用域。
为什么要包一层括号?因为以 function 开头的语句会被解析成函数声明,而声明不能直接调用。 外面套括号(或者前面加!、+、void)把它变成表达式。
当年解决什么问题:ES5 没有块作用域和模块, 所有 <script> 共享全局命名空间。 IIFE 是唯一的隔离手段—— jQuery 插件、UMD 打包产物全是这么写的。
会追问(这才是这题的重点):「现在还需要吗?」——基本不需要了: 块作用域 + let 能隔离变量, ES 模块天然有自己的作用域。
还剩两个场合会用到: ① 需要在顶层 await而环境不支持时,包一个(async () => { … })(); ② 打包工具生成的产物里。
我们那道 fetch 变式题里useEffect 内部包的(async () => {…})()就是场合 ①—— effect 不能是 async, 所以用 IIFE 开一个异步作用域。
In one line: an Immediately Invoked Function Expression — defined and called on the spot, in order to create an isolated scope.
Why the extra parentheses? Because a statement that starts with function is parsed as a function declaration, and a declaration cannot be called directly. Wrapping it in parentheses (or putting !, + or void in front) turns it into an expression.
What it solved back then: ES5 had no block scope and no modules, and every <script> shared one global namespace. An IIFE was the only way to isolate anything — jQuery plugins and UMD bundles are all written that way.
Follow-up, and this is the point of the question: “Do you still need it?” — mostly not: block scope plus let isolates variables, and an ES module has a scope of its own already.
Two situations are left: ① you need await at the top level and the environment does not support it, so you wrap a (async () => { … })(); ② inside output generated by a bundler.
The (async () => {…})() inside useEffect in our fetch variant exercise is case ① — an effect cannot be async, so an IIFE opens an async scope for it.