function 与 + - !~
為什么80%的碼農(nóng)都做不了架構(gòu)師?>>> ??
最近有空可以讓我靜下心來看看各種代碼,function與感嘆號(hào)的頻繁出現(xiàn),讓我回想起2個(gè)月前我回杭州最后參加團(tuán)隊(duì)會(huì)議的時(shí)候,
@西子劍影拋出的一樣的問題:
如果在function之前加上感嘆號(hào) (!) 會(huì)怎么樣?比如下面的代碼:
!function(){alert('iifksp')}() // true在控制臺(tái)運(yùn)行后得到的值時(shí)true,為什么是true這很容易理解,因?yàn)檫@個(gè)匿名函數(shù)沒有返回值,默認(rèn)返回的就是undefined,求反的結(jié)果很自然的就是true。所以問題并不在于結(jié)果值,而是在于,為什么求反操作能夠讓一個(gè)匿名函數(shù)的自調(diào)變的合法?
平時(shí)我們可能對(duì)添加括號(hào)來調(diào)用匿名函數(shù)的方式更為習(xí)慣:
(function(){alert('iifksp')})() // true或者:
(function(){alert('iifksp')}()) // true雖然上述兩者括號(hào)的位置不同,不過效果完全一樣。
那么,是什么好處使得為數(shù)不少的人對(duì)這種嘆號(hào)的方式情有獨(dú)鐘?如果只是為了節(jié)約一個(gè)字符未免太沒有必要了,這樣算來即使一個(gè)100K的庫恐怕也節(jié)省不了多少空間。既然不是空間,那么就是說也許還有時(shí)間上的考量,事實(shí)很難說清,文章的最后有提到性能。
回到核心問題,為什么能這么做?甚至更為核心的問題是,為什么必須這么做?
其實(shí)無論是括號(hào),還是感嘆號(hào),讓整個(gè)語句合法做的事情只有一件,就是讓一個(gè)函數(shù)聲明語句變成了一個(gè)表達(dá)式。
function a(){alert('iifksp')} // undefined這是一個(gè)函數(shù)聲明,如果在這么一個(gè)聲明后直接加上括號(hào)調(diào)用,解析器自然不會(huì)理解而報(bào)錯(cuò):
function a(){alert('iifksp')}() // SyntaxError: unexpected_token因?yàn)檫@樣的代碼混淆了函數(shù)聲明和函數(shù)調(diào)用,以這種方式聲明的函數(shù)?a,就應(yīng)該以?a();?的方式調(diào)用。
但是括號(hào)則不同,它將一個(gè)函數(shù)聲明轉(zhuǎn)化成了一個(gè)表達(dá)式,解析器不再以函數(shù)聲明的方式處理函數(shù)a,而是作為一個(gè)函數(shù)表達(dá)式處理,也因此只有在程序執(zhí)行到函數(shù)a時(shí)它才能被訪問。
所以,任何消除函數(shù)聲明和函數(shù)表達(dá)式間歧義的方法,都可以被解析器正確識(shí)別。比如:
var i = function(){return 10}(); // undefined 1 && function(){return true}(); // true 1, function(){alert('iifksp')}(); // undefined賦值,邏輯,甚至是逗號(hào),各種操作符都可以告訴解析器,這個(gè)不是函數(shù)聲明,它是個(gè)函數(shù)表達(dá)式。并且,對(duì)函數(shù)一元運(yùn)算可以算的上是消除歧義最快的方式,感嘆號(hào)只是其中之一,如果不在乎返回值,這些一元運(yùn)算都是有效的:
!function(){alert('iifksp')}() // true +function(){alert('iifksp')}() // NaN -function(){alert('iifksp')}() // NaN ~function(){alert('iifksp')}() // -1甚至下面這些關(guān)鍵字,都能很好的工作:
void function(){alert('iifksp')}() // undefined new function(){alert('iifksp')}() // Object delete function(){alert('iifksp')}() // true最后,括號(hào)做的事情也是一樣的,消除歧義才是它真正的工作,而不是把函數(shù)作為一個(gè)整體,所以無論括號(hào)括在聲明上還是把整個(gè)函數(shù)都括在里面,都是合法的:
(function(){alert('iifksp')})() // undefined (function(){alert('iifksp')}()) // undefined說了這么多,實(shí)則在說的一些都是最為基礎(chǔ)的概念——語句,表達(dá)式,表達(dá)式語句,這些概念如同指針與指針變量一樣容易產(chǎn)生混淆。雖然這種混淆對(duì)編程無表征影響,但卻是一塊絆腳石隨時(shí)可能因?yàn)樗^破血流。
最后討論下性能。我在jsperf上簡單建立了一個(gè)測試:http://jsperf.com/js-funcion-expression-speed?,可以用不同瀏覽器訪問,運(yùn)行測試查看結(jié)果。:
| !function(){;}() | 3,773,196 | 10,975,198 | 572,694 | 2,810,197 |
| +function(){;}() | 21,553,847 | 12,135,960 | 572,694 | 1,812,238 |
| -function(){;}() | 21,553,847 | 12,135,960 | 572,694 | 1,864,155 |
| ~function(){;}() | 3,551,136 | 3,651,652 | 572,694 | 1,876,002 |
| (function(){;})() | 3,914,953 | 12,135,960 | 572,694 | 3,025,608 |
| (function(){;}()) | 4,075,201 | 12,135,960 | 572,694 | 3,025,608 |
| void function(){;}() | 4,030,756 | 12,135,960 | 572,694 | 3,025,608 |
| new function(){;}() | 619,606 | 299,100 | 407,104 | 816,903 |
| delete function(){;}() | 4,816,225 | 12,135,960 | 572,694 | 2,693,524 |
| var i = function(){;}() | 4,984,774 | 12,135,960 | 565,982 | 2,602,630 |
| 1 && function(){;}() | 5,307,200 | 4,393,486 | 572,694 | 2,565,645 |
| 0 || function(){;}() | 5,000,000 | 4,406,035 | 572,694 | 2,490,128 |
| 1 & function(){;}() | 4,918,209 | 12,135,960 | 572,694 | 1,705,551 |
| 1 | function(){;}() | 4,859,802 | 12,135,960 | 572,694 | 1,612,372 |
| 1 ^ function(){;}() | 4,654,916 | 12,135,960 | 572,694 | 1,579,778 |
| 1, function(){;}() | 4,878,193 | 12,135,960 | 572,694 | 2,281,186 |
可見不同的方式產(chǎn)生的結(jié)果并不相同,而且,差別很大,因?yàn)g覽器而異。
但我們還是可以從中找出很多共性:new方法永遠(yuǎn)最慢——這也是理所當(dāng)然的。其它方面很多差距其實(shí)不大,但有一點(diǎn)可以肯定的是,感嘆號(hào)并非最為理想的選擇。反觀傳統(tǒng)的括號(hào),在測試?yán)锉憩F(xiàn)始終很快,在大多數(shù)情況下比感嘆號(hào)更快——所以平時(shí)我們常用的方式毫無問題,甚至可以說是最優(yōu)的。加減號(hào)在chrome表現(xiàn)驚人,而且在其他瀏覽器下也普遍很快,相比感嘆號(hào)效果更好。
當(dāng)然這只是個(gè)簡單測試,不能說明問題。但有些結(jié)論是有意義的:括號(hào)和加減號(hào)最優(yōu)。
但是為什么這么多開發(fā)者鐘情于感嘆號(hào)?我覺得這只是一個(gè)習(xí)慣問題,它們之間的優(yōu)劣完全可以忽略。一旦習(xí)慣了一種代碼風(fēng)格,那么這種約定會(huì)使得程序從混亂變得可讀。如果習(xí)慣了感嘆號(hào),我不得不承認(rèn),它比括號(hào)有更好的可讀性。我不用在閱讀時(shí)留意括號(hào)的匹配,也不用在編寫時(shí)粗心遺忘——
當(dāng)我也這么干然后嚷嚷著這居然又節(jié)省了一個(gè)字符而沾沾自喜的時(shí)候,卻忘了自己倉皇翻出一本卷邊的C語言教科書的窘迫和荒唐......任何人都有忘記的時(shí)候,當(dāng)再撿起來的時(shí)候,撿起的就已經(jīng)不單單是忘掉的東西了。
2011-10-31更新:如果你使用aptana,那么在使用(!+-)時(shí)要注意一點(diǎn),它們會(huì)讓aptana的解析失效,導(dǎo)致Outline窗口沒有任何顯示。但是就代碼本身而言,其運(yùn)行沒有任何問題。
轉(zhuǎn)載于:https://my.oschina.net/myzyq/blog/712163
總結(jié)
以上是生活随笔為你收集整理的function 与 + - !~的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: unity, eulerAngle
- 下一篇: 在eclipse中把项目部署到tomca