若是在function以前加上感叹号 (!) 会怎么样?好比下面的代码:html !function(){alert('iifksp')}() // truechrome 在控制台运行后获得的值时true,为何是true这很容易理解,由于这个匿名函数没有返回值,默认返回的就是undefined,求反的结果很天然的就是true。因此问题并不在于结果值,而是在于,为何求反操做可以让一个匿名函数的自调变的合法?express 平时咱们可能对添加括号来调用匿名函数的方式更为习惯:编程 (function(){alert('iifksp')})() // true浏览器 或者:jsp (function(){alert('iifksp')}()) // true函数
虽然上述二者括号的位置不一样,不过效果彻底同样。性能 那么,是什么好处使得为数很多的人对这种叹号的方式情有独钟?若是只是为了节约一个字符未免太没有必要了,这样算来即便一个100K的库恐怕也节省不了多少空间。既然不是空间,那么就是说也许还有时间上的考量,事实很难说清,文章的最后有提到性能。测试 回到核心问题,为何能这么作?甚至更为核心的问题是,为何必须这么作?spa 其实不管是括号,仍是感叹号,让整个语句合法作的事情只有一件,就是让一个函数声明语句变成了一个表达式。 function a(){alert('iifksp')} // undefined 这是一个函数声明,若是在这么一个声明后直接加上括号调用,解析器天然不会理解而报错: function a(){alert('iifksp')}() // SyntaxError: unexpected_token
由于这样的代码混淆了函数声明和函数调用,以这种方式声明的函数a,就应该以 a(); 的方式调用。 可是括号则不一样,它将一个函数声明转化成了一个表达式,解析器再也不以函数声明的方式处理函数a,而是做为一个函数表达式处理,也所以只有在程序执行到函数a时它才能被访问。 因此,任何消除函数声明和函数表达式间歧义的方法,均可以被解析器正确识别。好比: var i = function(){return 10}(); // undefined 赋值,逻辑,甚至是逗号,各类操做符均可以告诉解析器,这个不是函数声明,它是个函数表达式。而且,对函数一元运算能够算的上是消除歧义最快的方式,感叹号只是其中之一,若是不在意返回值,这些一元运算都是有效的: !function(){alert('iifksp')}() // true 甚至下面这些关键字,都能很好的工做: void function(){alert('iifksp')}() // undefined
最后,括号作的事情也是同样的,消除歧义才是它真正的工做,而不是把函数做为一个总体,因此不管括号括在声明上仍是把整个函数都括在里面,都是合法的: (function(){alert('iifksp')})() // undefined 说了这么多,实则在说的一些都是最为基础的概念——语句,表达式,表达式语句,这些概念如同指针与指针变量同样容易产生混淆。虽然这种混淆对编程无表征影响,但倒是一块绊脚石随时可能由于它而头破血流。 最后讨论下性能。我在jsperf上简单创建了一个测试:http://jsperf.com/js-funcion-expression-speed,能够用不一样浏览器访问,运行测试查看结果。我也同时将结果罗列以下表所示(因为我比较穷,测试配置有点丢人不过那也没办法:奔腾双核1.4G,2G内存,win7企业版):
可见不一样的方式产生的结果并不相同,并且,差异很大,因浏览器而异。 但咱们仍是能够从中找出不少共性:new方法永远最慢——这也是理所固然的。其它方面不少差距其实不大,但有一点能够确定的是,感叹号并不是最为理想的选择。反观传统的括号,在测试里表现始终很快,在大多数状况下比感叹号更快——因此平时咱们经常使用的方式毫无问题,甚至能够说是最优的。加减号在chrome表现惊人,并且在其余浏览器下也广泛很快,相比感叹号效果更好。 固然这只是个简单测试,不能说明问题。但有些结论是有意义的:括号和加减号最优。 可是为何这么多开发者钟情于感叹号?我以为这只是一个习惯问题,它们之间的优劣彻底能够忽略。一旦习惯了一种代码风格,那么这种约定会使得程序从混乱变得可读。若是习惯了感叹号,我不得不认可,它比括号有更好的可读性。我不用在阅读时留意括号的匹配,也不用在编写时粗心遗忘—— |