在学习函数声明和函数表达式之前如果你对作用域和作用域链掌握的不是特别的好,建议您先看完js深入理解函数作用域和作用域链,再进行接下来的学习
函数声明:function 函数名(){}
函数表达式:function 函数名(){},函数名,可写可不写,有名函数是命名函数表达式,无函数名是匿名函数表达式
长得那么像,怎么判断是函数声明还是函数表达式呢?其实就是看上下文判断的
var a = function aaa(){}、(function aaa(){})、以及在前面加位于运算符的都是函数表达式,(~、+、-、!……)
函数声明和函数表达式的区别是什么?
1、函数表达式可以直接在后面加括号执行,而函数声明不可以
2、函数声明在js解析时进行函数提升,因此在同一个作用域内,不管函数声明在哪里定义,该函数都可以进行调用。而函数表达式的值实在js运行时确定的,并且在表达式赋值完之后,该函数才能调用。
FunctionDeclaration(函数声明)只能出现在Program(程序)或FunctionBody(函数体)内。从句法上讲,它们 不能出现在Block(块)({ ... })中,例如不能出现在 if、while 或 for 语句中。因为 Block(块) 中只能包含Statement(语句), 而不能包含FunctionDeclaration(函数声明)这样的SourceElement(源元素)。
另一方面,仔细看一看产生规则也会发现,唯一可能让Expression(表达式)出现在Block(块)中情形,就是让它作为ExpressionStatement(表达式语句)的一部分。但是,规范明确规定了ExpressionStatement(表达式语句)不能以关键字function开头。而这实际上就是说,FunctionExpression(函数表达式)同样也不能出现在Statement(语句)或Block(块)中(别忘了Block(块)就是由Statement(语句)构成的)。
由于存在上述限制,只要函数出现在块中(像上面例子中那样),实际上就应该将其看作一个语法错误,而不是什么函数声明或表达式。
聊完函数声明和函数表达式,现在我们来看看自执行函数是个什么鬼
自执行函数又被称为立即调用函数,就是函数声明后可以立即被执行,在js库中我们可以经常发现自执行函数的身影,现在我们就用实例来说一下什么是自执行函数。
经常需要一个函数自执行,可惜这一种写法是错的: 代码如下:
原因是前半段“function(){alert(1);}”被当成了函数声明,而不是一个函数表达式,从而让后面的“();”变得孤立,产生语法错。
按上面的分析,这一段代码虽说没有语法错,但也是不符合我们的预期的,因为这个函数并没有自执行。
代码如下:
综上,症结在于,如何明确代码描述的是一个函数表达式,而不是函数声明语句。
正确的写法多种多样,也各有利弊:
方法1:最前最后加括号
代码如下:
(function(){alert(1);}());
这是jslint推荐的写法,好处是,能提醒阅读代码的人,这段代码是一个整体。
例如,在有语法高亮匹配功能的编辑器里,光标在第一个左括号后时,最后一个右括号也会高亮,看代码的人一眼就可以看到这个整体。
不过,对于某些写代码不喜欢在行后加分号的同学,也会形成一些坑坑,例如以下代码会报运行错:
代码如下:
方法2:function外面加括号
代码如下:
(function(){alert(1);})();
这种做法比方法1少了一个代码整体性的好处。
方法3:function前面加运算符,常见的是!与void 。
代码如下:
!function(){alert(1);}();
void function(){alert(2);}();
下面附上汤姆大叔的博客对自执行函数的理解