为何多数JavaScript库在IIFE前添加非运算符(!)?
!? 这个问题问得好!很多刚啃JS库源码的同学都会注意到这个小细节,我来给你拆解清楚~
核心原因:把函数声明转成可立即调用的表达式
JavaScript的解析器有个规则:如果代码以function开头,默认会把它当成函数声明。而函数声明必须有名字,还不能直接跟()调用——你试试直接写下面这段代码,浏览器肯定报错:
function() { console.log('测试'); }()
报错原因是:Uncaught SyntaxError: Unexpected token ')',因为解析器不认“无名字的函数声明+直接调用”这种写法。
而加了!(或者+、-、~这类一元运算符)之后,情况就变了:一元运算符只能作用于表达式,不能作用于声明。解析器会立刻把后面的function(){}当成函数表达式,这时候就能直接跟()执行了,完全符合语法规则。
搭配!使用IIFE的优势
1. 更精简的写法
对比传统的包裹式IIFE (function(){})(),!function(){}()少了一个字符(省去了开头的()。对于追求极致体积的JS库来说,每一个字节都很重要,这种写法能帮着压缩出更小的文件。
2. 避免“代码粘连”的语法错误
如果前面的代码忘记写分号,直接写包裹式IIFE可能会踩坑。比如:
var count = 10 (function(){ /* 内部逻辑 */ })()
解析器会把它误读成count = 10(function(){...})()——把10当成函数去调用,直接抛出错误。
但如果用!开头:
var count = 10 !function(){ /* 内部逻辑 */ }()
JavaScript的自动分号插入(ASI)规则会自动在两行之间补充分号,避免把10和后面的IIFE粘连在一起,减少潜在bug。
3. 不影响IIFE的核心功能
不管用哪种写法,IIFE的核心目的都是创建独立作用域、隔离变量、避免污染全局环境。!只是改变了表达式的解析方式,完全不会影响这个核心功能。
补充:不止!,这些写法原理一样
你可能还会看到库用+function(){}()、-function(){}()、~function(){}(),它们的原理和!完全一致——都是用一元运算符把函数声明转成可立即调用的表达式。只是!是最常用的,因为它看起来直观,而且不会改变返回值的类型(虽然大部分库也不在乎IIFE的返回值)。
内容的提问来源于stack exchange,提问作者user9016207

