2
  • 函数声明
function funcName(){

};
console.log(funcName); // 打印结果是funcName这个函数体。

声明一个函数funcName,funcName就是函数名,函数名是函数声明的必要组成部分,函数其实就是另一个类型的变量,函数名称相当于变量名,新声明的函数体会赋值给这个变量名,之后调用该函数的时候都需要通过该变量名进行调用。

  • 函数表达式
// 命名函数表达式
var funcName = function abc() {}; 
console.log(funcName); // 打印函数体function abc(){}
console.log(abc); // 报错(abc is not defined)

在这个函数表达式中,函数名称为abc,其实上,这个名称abc变成了函数内部的一个局部变量,并且指代函数对象本身,在abc函数内部打印abc的打印结果是abc函数体本身。

var funcName = function abc() {
    console.log(abc); // 打印结果是function abc() {console.log(abc)}
}; 

所以,在全局console.log(abc);肯定会报错,因为abc是局部变量,全局是拿不到的,这个函数表达式会忽略函数的名称,调用的时候要通过变量名进行调用——funcName();

// 匿名函数表达式
var funcName = function () {}; 

匿名函数表达式顾名思义就是没有名字的函数表达式,一般情况下,我们所说函数表达式就指匿名函数表达式,因为函数表达式会忽略函数的名称,会变成匿名函数表达式,不如直接写成匿名函数表达式。

函数表达式与函数声明不同的是,函数声明只是声明了一个函数,在预编译的时候,函数声明的声明提升函数体也提升,所以不管你是在函数声明之前调用还是在之后调用,都能正常执行。

demo(); // 结果是'a'
function demo(){
    console.log('a'); 
};
demo(); // 结果是'a'

而函数表达式在预编译时,是变量名提升,只有当执行到函数表达式所在行的代码时,才将函数体赋值给该变量,所以在函数表达式之前调用该函数会报错,只能在之后调用。

demo(); // 报错
var demo = function (){
    console.log('a')
};
demo(); // 结果是'a'
  • 匿名函数

匿名函数顾名思义就是没有名字的函数。(匿名函数有多种用途,写在文末)

function () {};

既然是没有名字的函数,那我们要怎样找到它调用它呢?这里要提到两种方法。

第一种方法是上面已经说到的匿名函数表达式,即将匿名函数赋值给一个变量,然后通过变量名去调用。

var abc = function (){};
abc(); 

第二种方法就是接下来要说的立即执行函数。

  • 立即执行函数

立即执行函数有两种写法:

// 第一种 w3c标准建议使用这一种
(function (){})();

// 第二种
(function(){}());

这里有两个括号有点疑问,在解释两个括号的作用前,我们先明确几点:
1.只有表达式才能被执行符号执行,函数声明是不能被执行符号执行的。
2.能被执行符号执行的表达式,这个函数的名字就会被自动忽略(放弃名字)。
3.能被执行符号执行的表达式基本上就是立即执行函数。

因为函数声明是不能被执行符号执行的,除非通过函数名调用,只有表达式才能被执行符号执行(匿名函数又没有函数名,另外的办法就是把它变成表达式)。

function (){
    console.log('a'); // 报语法错误,因为只有表达式才能被执行符号()执行
}();

(function (){})()
所以此处匿名函数两边的括号运算符,作用是把函数转换为表达式(至于怎样转换的,更深层的原理有兴趣的童鞋可以研究研究,后续我会进行补充的),后面的括号为执行符号(function (){})()就相当于匿名函数表达式的执行。

(function (){})()和(function(){}())写法其实没多大区别,(function(){}())也是一直等价的表达式,但是w3c标准建议使用第一种。


将函数声明转化成表达式的方式有很多,例如把它赋值给一个变量,再例如在函数声明前放上+运算符,-运算符,!运算符等。

// 把它赋值给一个变量
var demo = function(a){
 
  console.log(a); // 结果为1
 
}(1)
// 使用+运算符
+function(a){
 
  console.log(a); // 结果为1
 
}(1);
 
 // 使用-运算符
-function(a){
 
  console.log(a); // 结果为1
 
}(1);
 
 // 使用!运算符
!function(a){
 
  console.log(a); // 结果为1
 
}(1);

当表达式被执行,函数的名字就会被放弃,举两个栗子:

var demo = function(){}();
console.log(demo); // 结果会报错,因为函数名被放弃了。

+function demo(){}();
console.log(demo); // 结果会报错,因为函数名被放弃了。

匿名函数有很多作用,例如将匿名函数赋予一个变量来创建一个函数,例如赋予一个事件则成为事件处理程序,再例如用立即执行函数创建闭包防止污染全局变量等等

// 将匿名函数赋予一个变量来创建一个函数
var demo = function(){};

// 赋予一个事件则成为事件处理程序
$(selector).on('click',function(){});

// 用立即执行函数创建闭包
(function(window, undefined))(window);

本文只是简单分析以助自己理清思路,有错误之处请不吝赐教。


CelesteW
11 声望4 粉丝

不想当产品经理的画师不是好程序员(ˉ▽ ̄~)