理解 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 相关文章推荐
JSON 客户端和服务器端的格式转换
Aug 27 Javascript
在IE6下发生Internet Explorer cannot open the Internet site错误
Jun 21 Javascript
JS分页效果示例
Oct 11 Javascript
九种原生js动画效果
Nov 11 Javascript
使用Object.defineProperty实现简单的js双向绑定
Apr 15 Javascript
js for循环倒序输出数组元素的实例
Mar 01 Javascript
AngularJS实现根据不同条件显示不同控件
Apr 20 Javascript
JS实现简单的选择题测评系统代码思路详解(demo)
Sep 03 Javascript
vue中进入详情页记住滚动位置的方法(keep-alive)
Sep 21 Javascript
怎样在vue项目下添加ESLint的方法
May 16 Javascript
vue实现移动端触屏拖拽功能
Aug 21 Javascript
微信小程序向Java后台传输参数的方法实现
Dec 10 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 一个比较完善的简单文件上传
2010/03/25 PHP
php Smarty 字符比较代码
2011/02/27 PHP
Warning: session_destroy() : Trying to destroy uninitialized sessionq错误
2011/06/16 PHP
PHP 二维数组根据某个字段排序的具体实现
2014/06/03 PHP
Codeigniter实现多文件上传并创建多个缩略图
2014/06/12 PHP
PHP获取QQ达人QQ信息的方法
2015/03/05 PHP
PHP的命令行命令使用指南
2015/08/18 PHP
php获取汉字拼音首字母的方法
2015/10/21 PHP
PHP url的pathinfo模式加载不同控制器的简单实现
2016/08/12 PHP
PHP利用正则表达式将相对路径转成绝对路径的方法示例
2017/02/28 PHP
PHP+iframe模拟Ajax上传文件功能示例
2019/07/02 PHP
用Javascript实现锚点(Anchor)间平滑跳转
2009/09/08 Javascript
读jQuery之九 一些瑕疵说明
2011/06/21 Javascript
js实现一个省市区三级联动选择框代码分享
2013/03/06 Javascript
JS 实现导航栏悬停效果(续2)
2013/09/24 Javascript
js实现仿百度瀑布流的方法
2015/02/05 Javascript
jQuery实现仿腾讯视频列表分页效果的方法
2015/08/07 Javascript
JavaScript制作简单的日历效果
2016/03/10 Javascript
15位和18位身份证JS校验的简单实例
2016/07/18 Javascript
很棒的js Tab选项卡切换效果
2016/08/30 Javascript
bootstrap时间控件daterangepicker使用方法及各种小bug修复
2017/10/25 Javascript
微信小程序实现刷脸登录
2018/05/25 Javascript
深入理解react-router 路由的实现原理
2018/09/26 Javascript
详解vue 图片上传功能
2019/04/30 Javascript
javascript设计模式 ? 工厂模式原理与应用实例分析
2020/04/09 Javascript
[01:06:54]DOTA2-DPC中国联赛 正赛 RNG vs Dragon BO3 第一场 1月24日
2021/03/11 DOTA
python实现按任意键继续执行程序
2016/12/30 Python
实例讲解Python爬取网页数据
2018/07/08 Python
Python实现提取XML内容并保存到Excel中的方法
2018/09/01 Python
CSS3中animation实现流光按钮效果
2020/12/21 HTML / CSS
购买中国最好的电子产品:Geekbuying
2018/03/13 全球购物
J2EE面试题大全
2016/08/06 面试题
劳资员岗位职责
2013/11/11 职场文书
教师党员一句话承诺
2014/03/28 职场文书
寒假家长评语大全
2014/04/16 职场文书
小学社会实践活动总结
2014/07/03 职场文书