理解 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 相关文章推荐
jQuery学习4 浏览器的事件模型
Feb 07 Javascript
offsetParent 算法分析
Apr 05 Javascript
HTML中的setCapture和releaseCapture使用介绍
Mar 21 Javascript
jquery js 获取时间差、时间格式具体代码
Jun 05 Javascript
JSON中双引号的轮回使用过程中一定要小心
Mar 05 Javascript
单击某一段文字改写文本颜色
Jun 06 Javascript
node.js 开发指南 ? Node.js 连接 MySQL 并进行数据库操作
Jul 29 Javascript
jquery实现通用的内容渐显Tab选项卡效果
Sep 07 Javascript
js带缩略图的图片轮播效果代码分享
Sep 14 Javascript
jqueryMobile使用示例分享
Jan 12 Javascript
JavaScript的console命令使用实例
Dec 03 Javascript
Vue——解决报错 Computed property "****" was assigned to but it has no setter.
Dec 19 Vue.js
彻底解决 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
蝙蝠侠:侠影之谜
2020/03/04 欧美动漫
IIS下PHP连接数据库提示mysql undefined function mysql_connect()
2010/06/04 PHP
解析CodeIgniter自定义配置文件
2013/06/18 PHP
PHP中数据类型转换的三种方式
2015/04/02 PHP
WIFI万能钥匙密码查询接口实例
2015/09/28 PHP
谈谈PHP中substr和substring的正确用法及相关参数的介绍
2015/12/16 PHP
浅谈PHP中的Trait使用方法
2019/03/22 PHP
javascript的键盘控制事件说明
2008/04/15 Javascript
js left,right,mid函数
2008/06/10 Javascript
js鼠标点击事件在各个浏览器中的写法及Event对象属性介绍
2013/01/24 Javascript
html页面显示年月日时分秒和星期几的两种方式
2013/08/20 Javascript
使用js操作css实现js改变背景图片示例
2014/03/10 Javascript
最简单的JavaScript验证整数、小数、实数、有效位小数正则表达式
2015/04/17 Javascript
vue多级多选菜单组件开发
2020/09/08 Javascript
详解js的延迟对象、跨域、模板引擎、弹出层、AJAX【附实例下载】
2016/12/19 Javascript
微信小程序 表单Form实例详解(附源码)
2016/12/22 Javascript
详解jQuery事件
2017/01/13 Javascript
通俗解释JavaScript正则表达式快速记忆
2017/08/23 Javascript
vue短信验证性能优化如何写入localstorage中
2018/04/25 Javascript
在AngularJs中设置请求头信息(headers)的方法及不同方法的比较
2018/09/04 Javascript
Vue中使用ElementUI使用第三方图标库iconfont的示例
2018/10/11 Javascript
微信小程序 生成携带参数的二维码
2019/10/23 Javascript
Vue2.x和Vue3.x的双向绑定原理详解
2020/11/05 Javascript
Python中的集合类型知识讲解
2015/08/19 Python
python爬虫获取淘宝天猫商品详细参数
2020/06/23 Python
Python使用sorted对字典的key或value排序
2018/11/15 Python
python 通过类中一个方法获取另一个方法变量的实例
2019/01/22 Python
Python正则表达式实现简易计算器功能示例
2019/05/07 Python
python中dict使用方法详解
2019/07/17 Python
解决python -m pip install --upgrade pip 升级不成功问题
2020/03/05 Python
python 列表推导和生成器表达式的使用
2021/02/01 Python
HTML5在a标签内放置块级元素示例代码
2013/08/23 HTML / CSS
美国在线精品家居网站:Burke Decor
2017/04/12 全球购物
SNIDEL官网:日本VIVI杂志人气少女第一品牌
2020/03/12 全球购物
专业毕业生个性的自我评价
2013/10/03 职场文书
单位提档介绍信
2015/10/22 职场文书