有三种定义函数的方法,不同的定义方法应用场景不同但不是固定的。
ES6之前,函数可以定义在全局作用域和函数域中,严格来讲,在循环体、条件或其他语句块中定义函数都不合法。
在ES6严格模式下,函数声明可以出现在语句块中,但这个函数只在该语句块中有定义,对块的外部不可见。
函数声明
必须由function关键字、作为函数名的标识符、一对圆括号和包含函数体的一对花括号组成。
函数声明新定义了一个函数对象,这个函数对象赋值给了函数名(函数名就是一个变量,它引用了函数对象)
圆括号中包含用逗号分隔的形参,形参是函数体内的局部变量。
就算函数不执行任何操作,花括号也不可少,其内可以有零或多条语句。
function add(a,b){
let sum = 0;
sum = a + b;
return sum;
}
函数表达式
每一个表达式都会返回一个特定的值,函数表达式就是以表达式的形式定义的函数,形式和函数声明的形式一样,其中函数名是可选的。
function(x){return x * x;}
这是一个函数表达式,返回一个函数对象
通常情况下我们会将函数表达式赋值给一个变量或常量(赋给常量的话可以防止又意外给它赋予新值而重写函数),这样函数表达式就作为赋值语句的一部分。
const sum = function(x,y){return x + y;};
//赋值给sum后可以通过sum来调用该函数
sum(1,2);//3
通常情况函数表达式式不用函数名的
//函数表达式作为其它函数的参数
//sort()对数组元素进行排序,传入一个比较函数作为参数,返回排序后的数组
//如果比较函数的第一个参数要位于第二个参数之前,则比较函数应该返回一个小于零的数
//如果比较函数的第一个参数要位于第二个参数之后,则比较函数应该返回一个大于零的数
//如果比较函数的两个参数谁前谁后无所谓,则比较函数应该返回零
//按升序排
[90,23,45,22,-9,0].sort(function(x,y){return x - y;});
//函数表达式可以定义后立即调用
//最外层的括号不可少,否则JavaScript解释器会把function当做函数声明关键字来解析
//这种函数有个别名叫做:立即调用函数表达式
(function(x,y){return x + y;}(1,2));
箭头函数
箭头函数一般形式是:圆括号(里面是逗号分割的参数列表),后跟箭头=>,然后是包含在花括号中的函数体。(x,y) => {return x + y;}
这就是一个箭头函数。
//如果箭头函数只有一个参数,可以省略圆括号。
//下面两个表达式等效
(x) => x + x
x => x + x
//没有参数时圆括号不可以省。参数和箭头之间不可以换行
() => 12
//当函数体只有一个return语句,那么可以省略return关键字、语句末尾分号以及花括号
(x,y) => x + y
//返回值是一个对象时,要在对象字面量外加一对圆括号,否则解释器会把花括号当成函数体的括号来解析
x => {return {value:x};}
x => ({value:x})
箭头函数常作为值传给其他函数,如作为参数传给sort()函数
[90,23,45,22,-9,0].sort((x,y) => x - y);
区别
函数名
函数声明、函数表达式、箭头函数三种方式均创建了一个新的函数对象,后两种方式会把函数形象赋值给赋值表达式左边的变量,而函数声明会把函数对象赋值给函数名。
声明的“提升”
程序通常是由上至下执行。通过函数表达式和箭头函数定义的函数不可在其赋值之前调用。
但是通过函数声明方式定义的函数可以在声明之前调用,这就是函数声明方式特有的"提升",函数声明语句会被提升到1包含脚本、函数或代码块的顶部。
this的值
this关键字通常出现在函数体中。
对于通过函数声明和函数表达式定义的函数,当它们作为方法调用时,this指代调用它们的对象;当它们作为函数调用时,this指代全局对象(非严格模式)或undefined(严格模式)。而对于箭头函数而言,不管它是通过什么方式被调用,其this指代的是函数自身定义所在环境的this值。
而箭头函数不管它是如何被调用的,this指代的是其定义所在环境的this值
以上说法还有一个例外,构造函数的的this指代的是其新创建的对象,而跟它调用方式和声明方式无关。