理解 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 Lightbox 图片展示插件使用说明
Apr 25 Javascript
jquery 插件开发备注
Aug 27 Javascript
基于JQuery实现滚动到页面底端时自动加载更多信息
Jan 31 Javascript
js 操作符汇总
Nov 08 Javascript
深入分析js的冒泡事件
Dec 05 Javascript
jquery自定义表格样式
Nov 23 Javascript
如何用angularjs制作一个完整的表格
Jan 21 Javascript
JavaScript实现搜索框的自动完成功能(一)
Feb 25 Javascript
React.js入门实例教程之创建hello world 的5种方式
May 11 Javascript
linux 后台运行node服务指令方法
May 23 Javascript
vue中的数据绑定原理的实现
Jul 02 Javascript
谈谈IntersectionObserver懒加载的具体使用
Oct 15 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 CURL模拟登录新浪微博抓取页面内容 基于EaglePHP框架开发
2012/01/16 PHP
PHP基础之运算符的使用方法
2013/04/28 PHP
一个简单的PHP验证码实现代码
2014/05/10 PHP
php中隐形字符65279(utf-8的BOM头)问题
2014/08/16 PHP
ThinkPHP+EasyUI之ComboTree中的会计科目树形菜单实现方法
2017/06/09 PHP
php实现网页上一页下一页翻页过程详解
2019/06/28 PHP
php传值和传引用的区别点总结
2019/11/19 PHP
php操作redis数据库常见方法实例总结
2020/02/20 PHP
javascript setTimeout和setInterval计时的区别详解
2013/06/21 Javascript
JQuery判断radio(单选框)是否选中和获取选中值方法总结
2015/04/15 Javascript
使用console进行性能测试
2015/04/27 Javascript
jquery获得当前html页面源码的方法
2015/07/14 Javascript
JavaScript中数组的各种操作的总结(必看篇)
2017/02/13 Javascript
jQuery实现腾讯信用界面(自制刻度尺)样式
2017/08/15 jQuery
C#实现将一个字符转换为整数
2017/12/12 Javascript
在vue项目中引入highcharts图表的方法
2019/01/21 Javascript
VuePress 快速踩坑小结
2019/02/14 Javascript
微信小程序保存多张图片的实现方法
2019/03/05 Javascript
使用原生JS实现火锅点餐小程序(面向对象思想)
2019/12/10 Javascript
[46:16]2018DOTA2亚洲邀请赛3月30日 小组赛B组 iG VS VP
2018/03/31 DOTA
python生成日历实例解析
2014/08/21 Python
Python中让MySQL查询结果返回字典类型的方法
2014/08/22 Python
一个基于flask的web应用诞生 用户注册功能开发(5)
2017/04/11 Python
Python在图片中添加文字的两种方法
2017/04/29 Python
Python标准库之itertools库的使用方法
2017/09/07 Python
简单了解python的break、continue、pass
2019/07/08 Python
对Python中小整数对象池和大整数对象池的使用详解
2019/07/09 Python
python将print输出的信息保留到日志文件中
2019/09/27 Python
python中使用.py配置文件的方法详解
2020/11/23 Python
微软日本官方网站:Microsoft日本
2017/11/26 全球购物
介绍下WebSphere的安全性
2013/01/31 面试题
幼儿园母亲节活动方案
2014/03/10 职场文书
2014年四风问题自我剖析材料
2014/09/15 职场文书
绿里奇迹观后感
2015/06/15 职场文书
物资采购管理制度
2015/08/06 职场文书
详解Python flask的前后端交互
2022/03/31 Python