理解 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 相关文章推荐
多个iframe自动调整大小的问题
Sep 18 Javascript
在js中判断checkboxlist(.net控件客户端id)是否有选中
Apr 11 Javascript
Javascript中For In语句用法实例
May 14 Javascript
JavaScript+CSS实现仿天猫侧边网页菜单效果
Aug 25 Javascript
js实现仿百度风云榜可重复多次调用的TAB切换选项卡效果
Aug 31 Javascript
你应该知道的几类npm依赖包管理详解
Oct 06 Javascript
前端html中jQuery实现对文本的搜索功能并把搜索相关内容显示出来
Nov 14 jQuery
vue2中使用less简易教程
Mar 27 Javascript
vue鼠标悬停事件实例详解
Apr 01 Javascript
微信小程序可滑动月日历组件使用详解
Oct 21 Javascript
js实现简单掷骰子小游戏
Oct 24 Javascript
node.js中 mysql 增删改查操作及async,await处理实例分析
Feb 11 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
通过对php一些服务器端特性的配置加强php的安全
2006/10/09 PHP
PHP 替换模板变量实现步骤
2009/08/24 PHP
php利用递归实现删除文件目录的方法
2016/09/23 PHP
thinkPHP3.2.3实现阿里大于短信验证的方法
2018/06/06 PHP
javascript级联下拉列表实例代码(自写)
2013/05/10 Javascript
类似php的js数组的in_array函数自定义方法
2013/12/27 Javascript
详解iframe与frame的区别
2016/01/13 Javascript
vue.js项目中实用的小技巧汇总
2017/11/29 Javascript
VUE v-for循环中每个item节点动态绑定不同函数的实例
2018/09/26 Javascript
JavaScript中0、空字符串、'0'是true还是false的知识点分享
2019/09/16 Javascript
在layer弹层layer.prompt中,修改placeholder的实现方法
2019/09/27 Javascript
[01:28:31]《加油DOTA》真人秀 第五期
2014/09/01 DOTA
Python中正则表达式的用法实例汇总
2014/08/18 Python
python连接字符串的方法小结
2015/07/13 Python
python timestamp和datetime之间转换详解
2017/12/11 Python
unittest+coverage单元测试代码覆盖操作实例详解
2018/04/04 Python
详解Python修复遥感影像条带的两种方式
2020/02/23 Python
python矩阵运算,转置,逆运算,共轭矩阵实例
2020/05/11 Python
最新版 Windows10上安装Python 3.8.5的步骤详解
2020/11/28 Python
CSS3 filter(滤镜)实现网页灰色或者黑色模式的示例代码
2021/02/24 HTML / CSS
利用HTML5绘制点线面组成的3D图形的示例
2015/05/12 HTML / CSS
波兰在线运动商店:YesSport
2020/07/23 全球购物
Swanson中国官网:美国斯旺森健康产品公司
2021/03/01 全球购物
What is the purpose of Void class? Void类的作用是什么?
2016/10/31 面试题
应届大学生的推荐信
2013/11/20 职场文书
拓展训练激励口号
2014/06/17 职场文书
财务审计整改报告
2014/11/06 职场文书
2014年图书馆工作总结
2014/11/25 职场文书
地球一小时活动总结
2015/02/27 职场文书
活动新闻稿范文
2015/07/17 职场文书
党员干部学法用法心得体会
2016/01/21 职场文书
《这片土地是神圣的》教学反思
2016/02/16 职场文书
标准发言稿结尾
2019/07/18 职场文书
Python标准库之typing的用法(类型标注)
2021/06/02 Python
详解Java实践之建造者模式
2021/06/18 Java/Android
Python 的 sum() Pythonic 的求和方法详细
2021/10/16 Python