理解 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图片延迟加载 前端开发技能必备系列
Jun 18 Javascript
利用cookie记住背景颜色示例代码
Nov 04 Javascript
javascript的事件触发器介绍的实现
Jun 05 Javascript
JavaScript组合拼接字符串的效率对比测试
Nov 06 Javascript
基于js实现微信发送好友如何分享到朋友圈、微博
Nov 30 Javascript
JS实现六位字符密码输入器功能
Aug 19 Javascript
jQuery如何防止Ajax重复提交
Oct 14 Javascript
AngularJS深入探讨scope,继承结构,事件系统和生命周期
Nov 02 Javascript
jQuery模拟窗口抖动效果
Mar 15 Javascript
vue用Object.defineProperty手写一个简单的双向绑定的示例
Jul 09 Javascript
JS如何寻找数组中心索引过程解析
Jun 01 Javascript
如何利用JS将手机号中间四位变成*号
Sep 29 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
打造计数器DIY三步曲(中)
2006/10/09 PHP
php中全局变量global的使用演示代码
2011/05/18 PHP
php中邮箱地址正则表达式实现与详解
2012/04/24 PHP
Yii2使用自带的UploadedFile实现的文件上传
2016/06/20 PHP
PHP新特性之字节码缓存和内置服务器
2017/08/11 PHP
showModalDialog 和 showModelessDialog
2007/01/22 Javascript
js实现简单模态窗口,背景灰显
2008/11/14 Javascript
js 省地市级联选择
2010/02/07 Javascript
Javascript模块化编程(三)require.js的用法及功能介绍
2013/01/17 Javascript
js实现动画特效的文字链接鼠标悬停提示的方法
2015/03/02 Javascript
jQuery获得包含margin的outerWidth和outerHeight的方法
2015/03/25 Javascript
JQuery之proxy实现绑定代理方法
2016/08/01 Javascript
JS禁止查看网页源代码的实现方法
2016/10/12 Javascript
vue如何引入sass全局变量
2018/06/28 Javascript
代码整洁之道(重构)
2018/10/25 Javascript
Vant的安装和配合引入Vue.js项目里的方法步骤
2018/12/05 Javascript
ionic使用angularjs表单验证(模板验证)
2018/12/12 Javascript
javascript实现留言板功能
2020/02/08 Javascript
JS数据类型判断的几种常用方法
2020/07/07 Javascript
[03:40]DOTA2英雄梦之声_第01期_炼金术士
2014/06/23 DOTA
Django中redis的使用方法(包括安装、配置、启动)
2018/02/21 Python
Python异常处理操作实例详解
2018/08/28 Python
python实现将多个文件分配到多个文件夹的方法
2019/01/07 Python
python retrying模块的使用方法详解
2019/09/25 Python
Python编写打字训练小程序
2019/09/26 Python
Python数据可视化:饼状图的实例讲解
2019/12/07 Python
详解Python 函数参数的拆解
2020/09/02 Python
什么是servlet链?
2014/07/13 面试题
酒店实习个人鉴定
2013/12/07 职场文书
给女朋友的道歉信
2014/01/10 职场文书
考试没考好检讨书
2014/01/31 职场文书
反腐倡廉警示教育活动心得体会
2014/09/04 职场文书
高端收音机+蓝牙音箱,JBL TUNER FM带收音蓝牙音箱评测
2021/04/24 无线电
浅谈Python魔法方法
2021/06/28 Java/Android
MySQL系列之六 用户与授权
2021/07/02 MySQL
Python中的matplotlib绘制百分比堆叠柱状图,并为每一个类别设置不同的填充图案
2022/04/20 Python