理解 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 蒙版进度条(结合图片)
Mar 10 Javascript
jQuery实现大转盘抽奖活动仿QQ音乐代码分享
Aug 21 Javascript
jquery无限级联下拉菜单简单实例演示
Nov 23 Javascript
JavaScript时间操作之年月日星期级联操作
Jan 15 Javascript
JS查找字符串中出现最多的字符及个数统计
Feb 04 Javascript
jQuery实现获取隐藏div高度的方法示例
Feb 09 Javascript
javascript history对象详解
Feb 09 Javascript
使用命令行工具npm新创建一个vue项目的方法
Dec 27 Javascript
Vue监听数据渲染DOM完以后执行某个函数详解
Sep 11 Javascript
react配置antd按需加载的使用
Feb 11 Javascript
详解一些适用于Node.js的命名约定
Dec 08 Javascript
TypeScript之调用栈的实现
Dec 31 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时间不正确的解决方法
2008/04/09 PHP
基于PHP Web开发MVC框架的Smarty使用说明
2013/04/19 PHP
PHP实现json_decode不转义中文的方法
2017/05/20 PHP
PHP mongodb操作类定义与用法示例【适合mongodb2.x和mongodb3.x】
2018/06/16 PHP
PHP实现微信对账单处理
2018/10/01 PHP
javascript中String类的subString()方法和slice()方法
2011/05/24 Javascript
window.event快达到全浏览器支持了,以后使用就方便了
2011/11/30 Javascript
Js点击弹出下拉菜单效果实例
2013/08/12 Javascript
jquery实现点击弹出层效果的简单实例
2014/03/03 Javascript
常用的Javascript设计模式小结
2015/12/09 Javascript
深入理解JavaScript中Ajax
2016/08/02 Javascript
jQuery自定义插件详解及实例代码
2016/12/29 Javascript
jQuery插件HighCharts绘制2D金字塔图效果示例【附demo源码下载】
2017/03/09 Javascript
详解vue中router-link标签所必备了解的属性
2019/04/15 Javascript
Vue实现图片与文字混输效果
2019/12/04 Javascript
微信小程序上传帖子的实例代码(含有文字图片的微信验证)
2020/07/11 Javascript
JS实现拖动模糊框特效
2020/08/25 Javascript
Python sys.path详细介绍
2013/10/17 Python
Python中字典映射类型的学习教程
2015/08/20 Python
Python OpenCV实现图片上输出中文
2018/01/22 Python
基于Python开发chrome插件的方法分析
2018/07/07 Python
详解python分布式进程
2018/10/08 Python
python3常用的数据清洗方法(小结)
2019/10/31 Python
Python Pickle 实现在同一个文件中序列化多个对象
2019/12/30 Python
selenium设置浏览器为headless无头模式(Chrome和Firefox)
2021/01/08 Python
突袭HTML5之Javascript API扩展2—地理信息服务及地理位置API学习
2013/01/31 HTML / CSS
HTML5实现经典坦克大战坦克乱走还能发出一个子弹
2013/09/02 HTML / CSS
Ray-Ban雷朋美国官网:全球领先的太阳眼镜品牌
2016/07/20 全球购物
Bandier官网:奢侈、时尚前卫的健身服装首选目的地
2020/07/05 全球购物
七年级英语教学反思
2014/01/15 职场文书
联谊会主持词
2014/03/26 职场文书
文明寄语大全
2014/04/11 职场文书
2015年民主生活会发言材料
2014/12/15 职场文书
高三语文教学反思
2016/02/16 职场文书
超级实用!五步法则,教你写好年终工作总结
2019/12/05 职场文书
深入理解MySQL中MVCC与BufferPool缓存机制
2022/05/25 MySQL