理解 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 相关文章推荐
Ext第一周 史上最强学习笔记---GridPanel(基础篇)
Dec 29 Javascript
js 获取class的元素的方法 以及创建方法getElementsByClassName
Mar 11 Javascript
CSS+jQuery实现的一个放大缩小动画效果
Sep 24 Javascript
Jquery ajax执行顺序 返回自定义错误信息(实例讲解)
Nov 06 Javascript
js实现幻灯片播放图片示例代码
Nov 07 Javascript
node.js中的dns.getServers方法使用说明
Dec 08 Javascript
jQuery实现倒计时(倒计时年月日可自己输入)
Dec 02 Javascript
Angualrjs 表单验证的两种方式(失去焦点验证和点击提交验证)
May 09 Javascript
Angularjs 与 bower安装和使用详解
May 11 Javascript
javascript回调函数的概念理解与用法分析
May 27 Javascript
vue-cli3.0使用及部分配置详解
Aug 29 Javascript
在Vue中使用icon 字体图标的方法
Jun 14 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
长波有什么东西
2021/03/01 无线电
php 缩略图实现函数代码
2011/06/23 PHP
通过PHP的内置函数,通过DES算法对数据加密和解密
2012/06/21 PHP
PHP循环遍历数组的3种方法list()、each()和while总结
2014/11/19 PHP
php使用CURL模拟GET与POST向微信接口提交及获取数据的方法
2016/09/23 PHP
javascript数组组合成字符串的脚本
2021/01/06 Javascript
jQuery下通过$.browser来判断浏览器.
2011/04/05 Javascript
httpclient模拟登陆具体实现(使用js设置cookie)
2013/12/11 Javascript
js 数值转换为3位逗号分隔的示例代码
2014/02/19 Javascript
jQuery之Deferred对象详解
2014/09/04 Javascript
让DIV的滚动条自动滚动到最底部的3种方法(推荐)
2016/09/24 Javascript
网页挂马方式整理及详细介绍
2016/11/03 Javascript
vue.js父组件使用外部对象的方法示例
2017/04/25 Javascript
node中使用es5/6以及支持性与性能对比
2017/08/11 Javascript
JS实现的base64加密解密操作示例
2018/04/18 Javascript
js中火星坐标、百度坐标、WGS84坐标转换实现方法示例
2020/03/02 Javascript
[06:53]DOTA2每周TOP10 精彩击杀集锦vol.3
2014/06/25 DOTA
wxpython 学习笔记 第一天
2009/03/16 Python
教你学会使用Python正则表达式
2017/09/07 Python
Python如何获得百度统计API的数据并发送邮件示例代码
2019/01/27 Python
django中ORM模型常用的字段的使用方法
2019/03/05 Python
如何使用Python抓取网页tag操作
2020/02/14 Python
opencv 图像滤波(均值,方框,高斯,中值)
2020/07/08 Python
python爬虫看看虎牙女主播中谁最“顶”步骤详解
2020/12/01 Python
Python实现Word文档转换Markdown的示例
2020/12/22 Python
巴西女装购物网站:Eclectic
2018/04/24 全球购物
英国邮购活的植物主要供应商:Gardening Direct
2019/01/28 全球购物
Orlebar Brown官网:设计师泳裤和泳装
2020/12/08 全球购物
初中班主任寄语
2014/04/04 职场文书
还款承诺书范文
2014/05/20 职场文书
连锁超市项目计划书
2014/09/15 职场文书
党支部党的群众路线对照检查材料
2014/09/24 职场文书
大专毕业生自我鉴定范文(2篇)
2014/09/27 职场文书
聘任书的格式及模板
2019/10/28 职场文书
浅谈mysql哪些情况会导致索引失效
2021/11/20 MySQL
Apache SeaTunnel实现 非CDC数据抽取
2022/05/20 Servers