这是 小马 在交流会中的分享,可能有些朋友还不曾了解,同时也为了自己温故而知新,就整理下。
多种方式
可以想像得到,有很多方法立即执行匿名函数,简单的整理就有下面三种的典型方式(还有其他方式的,欢迎告知):
方式一
(function() {
// …
})();
方式二
void function() {
// …
}();
方式三
~function() {
// …
}();
方式一 和 方式二 大家可能都看到过,这里主要说明下 方式三。在说明 方式三 之前,我们现回顾下运算符「~
」(位取反)在 EMCAScript 中的定义(第五版的第 72 页),简单的翻译下:
- 按运算符结合语句
- 将旧值转换为 32 位整型
- 执行运算符后的语句
- 转换之行结果为 32 位整形并返回
从上面可以了解,其实位运算符都能立即返回后面表达式的值。其实其他位运算符都可以达到这样的目的,例如
!function() {
// …
}();
等都可以达到我们的目的。所以其实用「~
」也并无其他的原因,仅仅是代码「看着好看」而已 :^)
效率
与其说三种方式执行匿名函数的效率,到不如直接分析个运算符的执行效率。那么我们对比再来看看「()
」以及「void
」在 EMCA 规范中的定义
组运算符(第五版 66 页)
- 返回表达式的执行结果
void(第五版 70 页)
- 按运算符结合语句
- 执行
- 返回 undefined
由于组运算符还需要执行语句并返回语句块返回的值,对比 void 会多个获取语句块的操作(虽然消耗不了多少的性能),因此在这种情况下 void 的性能要优于组运算符。
对比两者,那么 方式三 的性能对比很明显要低于前两者。总结起来就是光从语法的角度上分析,在上面三者匿名函数的方式中 方式二 优于 方式一,方式三 的效率最低。
总结
思考下三者之间的优异
- 方式一的写法很常见而且很保险,所以并不会有人因为你使用这种方式而责怪你
- 但使用方式一的同学,可能经常会犯忘记匹配括号的「毛病」(特别是语句块很长时,就经常搞错)
- 使用位运算符执行匿名函数很新潮,用来装
逼酷不错 - 很多 IDE (如 IDEA )以及语法高亮工具不支持 方式三 的写法
- void 效率最好,但总感觉相比其他两种实现方式非常的臃肿(仅仅多几个字符?)
那么
- 综合代码量以及效率等情况考虑,用 方式一 没错的
- 在需要额外节省代码的极端情况,用 方式三
- 考虑效率优先,那么使用 方式二
这里要说明下,其实三种方式效率之间的差异非常小。因此单纯拿效率来考虑采用那种方式,几乎是站不住脚的。
具体采用何种方案,需要根据实际情况来考虑。比如我自己,经常会使用方式三,是因为 1、方便(加一个字符即可) 2、在函数长的情况下匹配括号会很头晕 3、用起来很酷,但 方式三 会经常让看我代码的组员感到困扰。
如果在些类库等框架性质的基础代码,用 方式一 最保险同时大家都容易看懂,是最保险的选择。
附
看见 阮一峰 的 Blog 上有篇文章说避免使用 void 运算符 。其实在 Javascript 中, void 的使用方面还是比较常见的。
例如,我们会强制让某些调用返回 undefined 以阻止浏览器等默认行为(我们经常看到的就比如很多 Javascript Bookmark 前面就经常会加上 void 运算符)。
所以,还是「物尽其用」吧。
-- EOF --
亲爱滴小贝, 感谢分享
这下装逼有着落了,挖哈哈哈
谢谢分享~~~
其实重点不在于前面放啥,比如
1,function()
{
alert(1);
}();
'-_-',function()
{
alert(2);
}();
+function()
alert(3);{
}();
-function()
alert(4);{
}();
1>>function()
{
alert(5);
}();
var a = function()
alert(6);{
}();
等等等等..
所以, 现象的原因才是重点^_^。
PS:狠喜欢您的博客,让我学到很多东西~
呃,怎么我的评论没了
@wait 被系统认为是垃圾评论了…我给您恢复回来了 :^)
让我更坚信《javascript语言精粹》是本垃圾书。
@dfs 兄弟言重了,书无分好坏只有认知的深浅,举一反三也未尝不是件好事
看了你的文章里提及了ECMA-262 第五版,有点困惑,查看了一些资料,感觉目前的主流还是第3版,现在就把5作为一个准则来参考会不会有点早
@kun10 的确,不过我写这篇 Blog 的时候手头上就只有第五版的,不过不妨碍文章的内容
顶dfs,虽然言过。不信春哥~
原来你也看阮一峰的博客;)
在团队的项目代码中用第三种方法,会不会被认为是装B