最近沒事喜歡看看,一些js庫的源碼,結果發現庫前不是加一個!就是加+或者一個(),心中猜出個大概知道這個是讓函數自動執行,可是這么多符號達到同一個目的,原理是什么呢,下面做一下剖析:
先從IIFE開始介紹
IIFE(Imdiately Invoked Function Expression 立即執行的函數表達式)
function(){ alert('IIFE'); }
把這個代碼放在console中執行會報錯
因為這個是一個匿名函數,要想讓它正常運行就必須給個函數名,然后通過函數名調用。
好了這下知道為啥我們看到很多類庫寫的時候也是匿名函數結果不報錯了吧,就是因為這些前面加的符號的原因。
其實在匿名函數前面加上這些符號后,就把一個函數聲明語句變成了一個函數表達式,是表達式就會在script標簽中自動執行。
運算符
①為什么加上了這些運算符后就能讓一個匿名函數變成一個不會報錯的函數表達式呢?
我們自然會想到javascript的解析器到底是怎么工作識別的呢,js解析器執行js表達式這個肯定是沒有問題的。其實無論是括號,還是感嘆號,讓整個語句合法做的事情只有一件,就是讓一個函數聲明語句變成了一個表達式。所以我們讓一個函數定義變成一個函數表達式來執行就不會報錯。
②原理
這樣是一個函數聲明 function a(){ alert('IIFE'); } 這樣是一個函數調用 a(); 理解一下就是在一個聲明了的函數后面加上一個()就可以調用函數了 function a(){ alert('IIFE'); }() 就這樣
但是我們按上面在console中執行發現出錯了
因為這樣的代碼混淆了函數聲明和函數調用,以這種方式聲明的函數 a
,就應該以 a();
的方式調用。
但是括號則不同,它將一個函數聲明轉化成了一個表達式,解析器不再以函數聲明的方式處理函數a,而是作為一個函數表達式處理,也因此只有在程序執行到函數a時它才能被訪問。所以,任何消除函數聲明和函數表達式間歧義的方法,都可以被解析器正確識別。所以,賦值,邏輯,甚至是逗號,各種操作符都可以告訴解析器,這個不是函數聲明,它是個函數表達式。並且,對函數一元運算可以算的上是消除歧義最快的方式,感嘆號只是其中之一,如果不在乎返回值,這些一元運算都是有效的
!function(){alert('iifksp')}() // true +function(){alert('iifksp')}() // NaN -function(){alert('iifksp')}() // NaN ~function(){alert('iifksp')}() // -1
性能
針對這些一元運算符,到底用哪個好呢,測試發現()的性能最優越,但是差別都不是特明顯,所以對於一個庫來說用幾個這樣的符號來說看不出什么影響,所以平常用! + -都可以,就看個人的代碼習慣,當然最好還是用()。
參考: