理解 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 相关文章推荐
讨论javascript(一)工厂方式 js面象对象的定义方法
Dec 15 Javascript
js阻止默认事件与js阻止事件冒泡示例分享 js阻止冒泡事件
Jan 27 Javascript
JavaScript中数据结构与算法(五):经典KMP算法
Jun 19 Javascript
认识Knockout及如何使用Knockout绑定上下文
Dec 25 Javascript
深入理解js数组的sort排序
May 28 Javascript
浅析JS获取url中的参数实例代码
Jun 14 Javascript
jQuery和hwSlider实现内容响应式可触控滑动切换效果附源码下载(二)
Jun 22 Javascript
基于jQuery ligerUI实现分页样式
Sep 18 Javascript
JS实现类似百叶窗下拉菜单效果
Dec 30 Javascript
js实现3D图片展示效果
Mar 09 Javascript
vue实例中data使用return包裹的方法
Aug 27 Javascript
webpack项目使用eslint建立代码规范实现
May 16 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 源代码压缩小工具
2009/12/22 PHP
php visitFile()遍历指定文件夹函数
2010/08/21 PHP
zf框架的Filter过滤器使用示例
2014/03/13 PHP
浅谈PDO的rowCount函数
2015/06/18 PHP
PHP多进程简单实例小结
2019/11/09 PHP
JS获取整个页面文档的实现代码
2011/12/15 Javascript
Jquery上传插件 uploadify v3.1使用说明
2012/06/18 Javascript
jquery实现焦点图片随机切换效果的方法
2015/03/12 Javascript
JavaScript实现Iterator模式实例分析
2015/06/09 Javascript
Bootstrap创建可折叠的组件
2016/02/23 Javascript
令按钮悬浮在(手机)页面底部的实现方法
2017/05/02 Javascript
微信小程序实现根据字母选择城市功能
2017/08/16 Javascript
微信小程序实现MUI数字输入框效果
2018/01/31 Javascript
vue 使用vue-i18n做全局中英文切换的方法
2018/10/29 Javascript
详解vue-cli 脚手架 安装
2019/04/16 Javascript
JS实现滑动导航效果
2020/01/14 Javascript
ES6 Generator基本使用方法示例
2020/06/06 Javascript
详解Django的CSRF认证实现
2018/10/09 Python
Python Matplotlib库安装与基本作图示例
2019/01/09 Python
详解pandas.DataFrame.plot() 画图函数
2020/06/14 Python
python如何实现读取并显示图片(不需要图形界面)
2020/07/08 Python
python中的垃圾回收(GC)机制
2020/09/21 Python
HTML5使用Audio标签实现歌词同步的效果
2016/03/17 HTML / CSS
国际领先的学术出版商:Springer
2017/01/11 全球购物
新东网科技Java笔试题
2012/07/13 面试题
C/C++ 笔试、面试题目大汇总
2015/11/21 面试题
.NET现在共支持多少种语言
2014/02/26 面试题
生产车间主任的个人自我鉴定
2013/10/25 职场文书
优秀少先队大队辅导员事迹材料
2014/05/04 职场文书
教师国庆节演讲稿范文2014
2014/09/21 职场文书
反四风对照检查材料
2014/09/22 职场文书
撤诉状格式范本
2015/05/19 职场文书
刑事案件上诉状
2015/05/23 职场文书
《月歌。》宣布制作10周年纪念剧场版《RABBITS KINGDOM THE MOVIE》
2022/04/02 日漫
Python 视频画质增强
2022/04/28 Python
MySQL 执行数据库更新update操作的时候数据库卡死了
2022/05/02 MySQL