(转) function与感叹号
原文:http://blog.sina.com.cn/s/blog_775f158f01016j12.html
function与感叹号(转)(2012-08-29 12:29:12)
最近有空可以让我静下心来看看各种代码,function与感叹号的频繁出现,让我回想起2个月前我回杭州最后参加团队会议的时候,@西子剑影抛出的一样的问题:如果在function之前加上感叹号 (!) 会怎么样?比如下面的代码:
!function(){alert('iifksp')}() // true
在控制台运行后得到的值时true,为什么是true这很容易理解,因为这个匿名函数没有返回值,默认返回的就是undefined,求反的结果很自然的就是true。所以问题并不在于结果值,而是在于,为什么求反操作能够让一个匿名函数的自调变的合法?
平时我们可能对添加括号来调用匿名函数的方式更为习惯:
(function(){alert('iifksp')})() // true
或者:
(function(){alert('iifksp')}()) // true
虽然上述两者括号的位置不同,不过效果完全一样。
那么,是什么好处使得为数不少的人对这种叹号的方式情有独钟?如果只是为了节约一个字符未免太没有必要了,这样算来即使一个100K的库恐怕也节省不了多少空间。既然不是空间,那么就是说也许还有时间上的考量,事实很难说清,文章的最后有提到性能。
回到核心问题,为什么能这么做?甚至更为核心的问题是,为什么必须这么做?
其实无论是括号,还是感叹号,让整个语句合法做的事情只有一件,就是让一个函数声明语句变成了一个表达式。
function a(){alert('iifksp')} // undefined
这是一个函数声明,如果在这么一个声明后直接加上括号调用,解析器自然不会理解而报错:
function a(){alert('iifksp')}() // SyntaxError: unexpected_token
因为这样的代码混淆了函数声明和函数调用,以这种方式声明的函数a,就应该以 a(); 的方式调用。
但是括号则不同,它将一个函数声明转化成了一个表达式,解析器不再以函数声明的方式处理函数a,而是作为一个函数表达式处理,也因此只有在程序执行到函数a时它才能被访问。
所以,任何消除函数声明和函数表达式间歧义的方法,都可以被解析器正确识别。比如:
var i = function(){return }(); // undefined
&& function(){return true}(); // true
, function(){alert('iifksp')}(); // undefined
赋值,逻辑,甚至是逗号,各种操作符都可以告诉解析器,这个不是函数声明,它是个函数表达式。并且,对函数一元运算可以算的上是消除歧义最快的方式,感叹号只是其中之一,如果不在乎返回值,这些一元运算都是有效的:
!function(){alert('iifksp')}() // true
+function(){alert('iifksp')}() // NaN
-function(){alert('iifksp')}() // NaN
~function(){alert('iifksp')}() // -1
甚至下面这些关键字,都能很好的工作:
void function(){alert('iifksp')}() // undefined
new function(){alert('iifksp')}() // Object
delete function(){alert('iifksp')}() // true
最后,括号做的事情也是一样的,消除歧义才是它真正的工作,而不是把函数作为一个整体,所以无论括号括在声明上还是把整个函数都括在里面,都是合法的:
(function(){alert('iifksp')})() // undefined
(function(){alert('iifksp')}()) // undefined
说了这么多,实则在说的一些都是最为基础的概念——语句,表达式,表达式语句,这些概念如同指针与指针变量一样容易产生混淆。虽然这种混淆对编程无表征影响,但却是一块绊脚石随时可能因为它而头破血流。
最后讨论下性能。我在jsperf上简单建立了一个测试:http://jsperf.com/js-funcion-expression-speed,可以用不同浏览器访问,运行测试查看结果。我也同时将结果罗列如下表所示(由于我比较穷,测试配置有点丢人不过那也没办法:奔腾双核1.4G,2G内存,win7企业版):
| Option | Code | Ops/sec | |||
|---|---|---|---|---|---|
| Chrome 13 | Firefox 6 | IE9 | Safari 5 | ||
| ! | !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 |
| (1) | (function(){;})() | 3,914,953 | 12,135,960 | 572,694 | 3,025,608 |
| (2) | (function(){;}()) | 4,075,201 | 12,135,960 | 572,694 | 3,025,608 |
| void | void function(){;}() | 4,030,756 | 12,135,960 | 572,694 | 3,025,608 |
| new | new function(){;}() | 619,606 | 299,100 | 407,104 | 816,903 |
| delete | 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 |
可见不同的方式产生的结果并不相同,而且,差别很大,因浏览器而异。
但我们还是可以从中找出很多共性:new方法永远最慢——这也是理所当然的。其它方面很多差距其实不大,但有一点可以肯定的是,感叹号并非最为理想的选择。反观传统的括号,在测试里表现始终很快,在大多数情况下比感叹号更快——所以平时我们常用的方式毫无问题,甚至可以说是最优的。加减号在chrome表现惊人,而且在其他浏览器下也普遍很快,相比感叹号效果更好。
当然这只是个简单测试,不能说明问题。但有些结论是有意义的:括号和加减号最优。
但是为什么这么多开发者钟情于感叹号?我觉得这只是一个习惯问题,它们之间的优劣完全可以忽略。一旦习惯了一种代码风格,那么这种约定会使得程序从混乱变得可读。如果习惯了感叹号,我不得不承认,它比括号有更好的可读性。我不用在阅读时留意括号的匹配,也不用在编写时粗心遗忘——
(转) function与感叹号的更多相关文章
- function与感叹号
原文链接:https://swordair.com/function-and-exclamation-mark/ 最近有空可以让我静下心来看看各种代码,function与感叹号的频繁出现,让我回想起2 ...
- [转载]function与感叹号
http://swordair.com/function-and-exclamation-mark/ 最近有空可以让我静下心来看看各种代码,function与感叹号的频繁出现,让我回想起2个月前我回杭 ...
- function和感叹号,运算符号的转化
1.下面的程序经过运算之后,a为true,这个很好理解,但是函数怎么会运行呢? var a = !function(){ alert('message'); }(); console.log(a); ...
- Javascript中的感叹号和函数function
js函数前加分号和感叹号是什么意思?有什么用?:http://www.cnblogs.com/mq0036/p/4605255.html function与感叹号:https://swordair.c ...
- 自执行的匿名函数!function()
最近有空可以让我静下心来看看各种代码,function与感叹号的频繁出现,让我回想起2个月前我回杭州最后参加团队会议的时候,@西子剑影抛出的一样的问题:如果在function之前加上感叹号 (!) 会 ...
- Bootstrap 4 中 Alerts 实现
Alert 的使用说明 http://v4-alpha.getbootstrap.com/components/alerts/ JavaScript behavior Triggers Enable ...
- 通过百度echarts实现数据图表展示功能
现在我们在工作中,在开发中都会或多或少的用到图表统计数据显示给用户.通过图表可以很直观的,直接的将数据呈现出来.这里我就介绍说一下利用百度开源的echarts图表技术实现的具体功能. 1.对于不太理解 ...
- javascript中的感叹号 "!"
JavaScript中会经常遇到一个操作符:! 这是一个布尔操作符,用于将操作的值强制转换为布尔值并取反.常用场景如下: //条件判断中使用 var a; var b=null; if(!a){ co ...
- js文件中函数前加分号和感叹号是什么意思?
本文转自:http://blog.csdn.net/h_o_w_e/article/details/51388500 !function(){}(); !有什么用? 从语法上来开,JavaScri ...
随机推荐
- 【转】 Linux下的多线程编程
作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/原文链接:http://www.cnblogs.com/gnuhpc/archive/2012/12/07/280 ...
- VS2012更改项目编译后文件输出目录
1.现在我的解决方案里有存在两个项目,分别是类库项目ClassLibrary1和控制台项目ConsoleApplication1,默认情况下当解决方案重新生成后,这两个项目所对应的编译后文件分别会存在 ...
- 使用AndroidStudio编译NDK的方法及错误解决方案
参考资料: [android ndk]macos环境下Android Studio中利用gradle编译jni模块及配置:http://demo.netfoucs.com/ashqal/article ...
- iOS开发数据库SQLite的使用
iOS系统自带Core Data来进行持久化处理,而且Core Data可以使用图形化界面来创建对象,但是Core Data不是关系型数据库,对于Core Data来说比较擅长管理在设备上创建的数据持 ...
- UserAgent:通过浏览器获取用户浏览器等信息
User Agent的含义 User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本.CPU 类型.浏览器及版本.浏览器渲染引擎.浏 ...
- bash: sqlplus: command not found 解决方法
在oracle用户下输入:sqlplus 抛出bash: sqlplus: command not found 解决办法: 在root用户下输入如下命令: ln -s $ORACLE_HOME/bin ...
- 在 Ubuntu 14.04/15.04 上配置 Node JS v4.0.0
大家好,Node.JS 4.0 发布了,这个流行的服务器端 JS 平台合并了 Node.js 和 io.js 的代码,4.0 版就是这两个项目结合的产物——现在合并为一个代码库.这次最主要的变化是 N ...
- SQL查询表占用空间大小
SQL查询表占用空间大小. create table tmp (name varchar(50),rows int,reserved varchar(50),data varchar(50),inde ...
- spring任务计划
小组 第一次小组会议结果 贾川和刘三龙负责这些任务: 1:4.11 搭配开发必要的环境,vs2010 2:4.12学习windows界面开发的基本知识 3:4.13-4.15 和小组成员讨论软件界面的 ...
- winform的comboBox使鼠标滑轮修改值失效
目标: winform窗体很多combobox下拉框,当他们其中的一个获得焦点的时候,如果滚动鼠标就会改变下拉框的值,要实现让鼠标滚轮不对下拉框的值造成影响 如下代码直接拷贝粘贴,不用修改 方法一: ...