(function(){}())与(function(){})()的区别

Wesley13
• 阅读 540

直接进入正题。请说出 immediately-invoked function expression(IIFE)的以下两种写法的区别:

(function () {
  // code here
})();

(function () {
  // code here
}());

嘛,从效果上来说,正如StackOverflow(SO)上的网友说的:“It genuinely doesn’t matter, so do whatever you prefer.”。好吧囧,不要拍砖,其实在语法层面上还是有区别的,以下配合引用SO上的CMS(这是网友id,不是那啥……)的描述来讲讲。

首先要明白以下写法是语法错误的:

function() {
 // code here
} ();

编译器会认为该表达式是函数声明,由于在‘function’与‘()’之间找不到函数名称而抛出语法错误。为了能够实现immediately-invoked,于是有了在讨论的两种写法。

对于第一种写法,通过将函数表达式的调用用括号包起来,使编译器理解括号内的代码是表达式而不是声明,从而能够正确解析:

CallExpression
                |         |
       FunctionExpression |
                |         |
                V         V
    (function() {       }());
    ^                      ^
    |--PrimaryExpression --|

对于第二种写法,其实也是通过括号将函数表达式包起来使编译器明白该函数表达式不是声明从而正确编译,然后立刻使用‘()’来调用这个函数:

PrimaryExpression
                |
         FunctionExpression
                |
                V
    (function() {       })();
    ^                      ^
    |--  CallExpression  --|

可以看出,两种写法的关键点就是通过将表达式放在‘()’中,使编译器能够正确识别其为函数表达式而不是声明。于是,其实下面的写法也都是可以的:

-function(){}();
+function(){}();
!function(){}();
...

呃……这些写法确实很是有趣,而且也比本文讨论的两种写法少了一个字符……但存在很大的缺陷。考虑下面的语句:

var obj = !function() {
    return {};
}();

很显然,不管函数里返回了什么,最后obj变量保存的都是true布尔值。而使用括号包住的方式则能正确返回Object对象。

ok,相信看官看到这里应该已经明白IIFE的写法了(如果你说这真是个很无聊的问题……其实我也是这么想XD~重要的是学习的过程啊亲)。那还有一个问题就是,使用哪种写法是比较推荐的呢?jQuery推荐第一种写法,而老道Crockford则推荐第二种。以下是老道这样推荐的原因:

“[...] and again, I’m wrapping the whole function and the invocation in parens. as a sign to the reader that there is something bigger going on than just an assignment of a function. There are some people who will put the golden paren. around the function and not around the whole invocation — that doesn’t make sense to me because what we are trying to tell the user is: ‘Look at the whole thing’, and putting parentheses around just part of it, I think, is counter-productive, so I think the whole thing needs to be wrapped in parens.” — Douglas Crockford.

大意是说:使用括号将函数与调用符一起包含起来,是为了告诉读者这是一个整体,而只包含函数表达式的写法对他来说没有意义。

但是我个人是比较习惯第一种写法的,将函数表达式与调用符通过括号分隔开,在我看来是更清晰的调用。嘛,仁者见仁智者见智,想怎么用就怎么用吧,这个问题上没什么好辩论的:)

最后是给看到文章末尾的人的福利哈哈。偶然看到的函数调用方式:

(a || b) && (a || b)()
// 等价于:
// a ? a() : (b && b());

虽然没想到什么场景下会有这样的调用,但觉得想到这个的人真有才…

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
风花雪月 风花雪月
3年前
警告Function name should be lowercase
用pyCharm时,常会出现警告信息:functionnameshouldbelowercase   函数名应该是小写 字母argumentnameshouldbelowercase参数名应该是小写字母variableinfunctionshouldbelowercase变量应该是小写字母 全是小写字母,可能与以往的习惯不大一
Stella981 Stella981
3年前
Lua基础(对象)
:和.区别.   stu{id100,name"Tom",age21}成员变量   function stu.toString()成员函数    return stu.id .. stu.name .. stu.age   endprint(stu
Stella981 Stella981
3年前
ES6中Generator理解
1\.生成器函数声明  function\ name(args){};2\.yield使用function hello(){    console.log('before hello');  //可看到hello()并不会立刻执行函数, 到第一次next调用时才会    var name 
Stella981 Stella981
3年前
JS 对象数组Array 根据对象object key的值排序sort,很风骚哦
有个js对象数组varary\{id:1,name:"b"},{id:2,name:"b"}\需求是根据name或者id的值来排序,这里有个风骚的函数函数定义:function keysrt(key,desc) {  return function(a,b){    return desc ? ~~(ak
Stella981 Stella981
3年前
Lua 函数
【1】函数定义Lua函数定义格式如下:1optional_function_scopefunctionfunction_name(argument1,argument2,argument3...,argumentn)2function_body3returnresult_params_comma_
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这