理解 javascript 中的函数表达式与函数声明


Posted in Javascript onJuly 07, 2017

常用闭包的同学肯定很清楚下面一段代码:

//通常的闭包写法
(function () {
 ...
}())

那么我们的问题来了,为什么要在 function () {...}() 之外用圆括号包裹呢?解答这个问题,就需要我们理解 Javascript 中函数表达式与函数声明的概念。

函数定义带来的错误

虽然 function () {...} 看上去像是一个函数声明,但是由于没有函数名,它的本质其实是一个函数表达式。我们看下规范中对于函数声明与函数表达式的定义:

理解 javascript 中的函数表达式与函数声明

可以看出来,函数声明是必须带有函数名的。所以在直接执行 function () {...}() 时候会报语法错误,原因就是函数表达式被尝试解析为函数声明时没有找到函数名。

理解 javascript 中的函数表达式与函数声明

那么我们继续尝试写上函数名的情况:

function fn () {...}()

理解 javascript 中的函数表达式与函数声明

仍然会提示语法错误,不过这次的出错的位置在后面 () 中的 ) 上。

先不解释为什么,看接下来的示例:

理解 javascript 中的函数表达式与函数声明

从这个结果可以看出,函数声明之后的 () 会被解析为分组运算符,而不是函数调用。那么如何才能使函数执行呢?

如何正确解析函数表达式

根据规范,函数表达式必须在 Expression 中才能进行正确的语法解析。恰巧 () 在作为分组运算符时,里面的内容会被认为是 Expression。

(function () {...}())
(function () {...})()

上述两种写法都是正确的。第一种写法比较清晰,函数表达式被正确解析并调用。第二种写法中,解析器首先处理 (function () {...}) 部分,由于分组运算符不会对其中内容进行 GetValue 操作,所以在语句结束时,其中的函数表达式被直接返回,之后的 () 则表示函数调用。

我们来简单的用一个例子表示一下:

var a = function () {...}
(a()) //形同 (function () {...}())
(a)() //形同 (function () {...})()

这个例子稍有不恰当,因为直接执行 a() 是可行的,而直接执行 function () {...}() 则不行,原因就是上面提到的,function () {...} 被尝试解析为函数声明而引发了语法错误。

其他方式

上面我们提到通过 () 分组运算符,可以将匿名函数正确的理解为函数表达式。同理,我们也可以通过许多其他的运算符将函数表达式正确执行。

!function () {}()
void function () {}()
+function () {}()
-function () {}()
if (function () {}()) {} 
...

由于很多操作符会改变函数返回值,比如 !function () {return 0}void function () {}()+ function () {}() 等,所以我们一般使用 () 将匿名函数包裹使其被正确解析为函数表达式。

参考文章

http://www.zhihu.com/question/40902815/answer/88787368

http://www.zhihu.com/question/20292224

Javascript 相关文章推荐
JS弹出层的显示与隐藏示例代码
Dec 27 Javascript
js判断字符长度以及中英文数字等
Dec 31 Javascript
js 通过html()及text()方法获取并设置p标签的显示值
May 14 Javascript
JavaScript数据类型之基本类型和引用类型的值
Apr 01 Javascript
基于jQuery.Hz2Py.js插件实现的汉字转拼音特效
May 07 Javascript
jquery-tips悬浮提示插件分享
Jul 31 Javascript
BootStrap selectpicker
Jun 20 Javascript
基于AngularJS实现的工资计算器实例
Jun 16 Javascript
vue2.0 兄弟组件(平级)通讯的实现代码
Jan 15 Javascript
vue elementui form表单验证的实现
Nov 11 Javascript
原生JS实现图片懒加载之页面性能优化
Apr 26 Javascript
js实现弹框效果
Mar 24 Javascript
彻底解决 webpack 打包文件体积过大问题
Jul 07 #Javascript
JS仿QQ好友列表展开、收缩功能(第一篇)
Jul 07 #Javascript
JS仿QQ好友列表展开、收缩功能(第二篇)
Jul 07 #Javascript
JS实现发送短信验证后按钮倒计时功能(防止刷新倒计时失效)
Jul 07 #Javascript
详解vue.js+UEditor集成 [前后端分离项目]
Jul 07 #Javascript
JS实现搜索关键词的智能提示功能
Jul 07 #Javascript
vue.js国际化 vue-i18n插件的使用详解
Jul 07 #Javascript
You might like
合并ThinkPHP配置文件以消除代码冗余的实现方法
2014/07/22 PHP
laravel5 Eloquent 实现事务方式
2019/10/21 PHP
PHP 8新特性简介
2020/08/18 PHP
CL vs ForZe BO5 第一场 2.13
2021/03/10 DOTA
javascript 清空form表单中某种元素的值
2009/12/26 Javascript
javascript中检测变量的类型的代码
2010/12/28 Javascript
关于IE BUG与字符串截取substr的解决办法
2013/04/10 Javascript
控制页面按钮在后台执行期间不重复提交的JS方法
2013/06/24 Javascript
IE6-8中Date不支持toISOString的修复方法
2014/05/04 Javascript
深入浅析JavaScript中的Function类型
2016/07/09 Javascript
Angular中使用ui router实现系统权限控制及开发遇到问题
2016/09/23 Javascript
RequireJS 依赖关系的实例(推荐)
2017/01/21 Javascript
JS实现css hover操作的方法示例
2017/04/07 Javascript
vue结合Echarts实现点击高亮效果的示例
2018/03/17 Javascript
详解vue-cli 构建项目 vue-cli请求后台接口 vue-cli使用axios、sass、swiper
2018/05/28 Javascript
vuex如何重置所有state(可定制)
2019/01/17 Javascript
arctext.js实现文字平滑弯曲弧形效果的插件
2019/05/13 Javascript
Vue.use()在new Vue() 之前使用的原因浅析
2019/08/26 Javascript
jQuery插件实现图片轮播效果
2020/10/19 jQuery
[57:55]EG vs Fnatic 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
Python中random模块生成随机数详解
2016/03/10 Python
Python+OpenCV目标跟踪实现基本的运动检测
2018/07/10 Python
Python unittest 简单实现参数化的方法
2018/11/30 Python
pycharm运行和调试不显示结果的解决方法
2018/11/30 Python
Python函数装饰器实现方法详解
2018/12/22 Python
celery4+django2定时任务的实现代码
2018/12/23 Python
python实现电子产品商店
2019/02/26 Python
Puma印度官网:德国运动品牌
2019/10/06 全球购物
精选鞋类、服装和配饰的全球领先目的地:Bodega
2021/02/27 全球购物
医学院毕业生自荐信
2013/11/08 职场文书
会计专业毕业生求职信分享
2014/01/03 职场文书
法律专业应届生自荐信范文
2014/01/06 职场文书
护士毕业实习感言
2014/03/05 职场文书
环保口号大全
2014/06/12 职场文书
MySQL 存储过程的优缺点分析
2021/05/20 MySQL
python热力图实现的完整实例
2022/06/25 Python