什么是箭头函数,如何使用
ECMAScript 6
新增了使用胖箭头(=>)语法定义函数表达式的能力。很大程度上,箭头函数实例化的函数对象与正式的函数表达式创建的函数对象行为是相同的。何可以使用表达式的地方,都可以使用箭头函数
let arrowSum = (a,b)=>{
return a + b;
}
let functionExpressionSum = function(a,b){
return a+ b;
}
console.log(arrowSum(3,5)); //8
console.log(functionExpressionSum(3,5)); //8
箭头函数简洁的语法非常适合嵌入函数的场景
let ints=[1,2,3]
console.log(ints.map(function(i){return i+1})); //[2, 3, 4]
console.log(ints.map((i)=>{return i+1})); //[2, 3, 4]
如果只有一个参数,那也可以不用括号。只有没有参数,或者多个参数的情况下,才需要使用括号
// 一下两种写法都有效
let double = (x)=>{
return 2*x;
}
let triple = x=>{
return 3*x
}
// 没有参数需要括号
let getRandom = ()=>{
return Math.random();
}
// 多个参数需要括号
let sun = (a,b)=>{
return a+b;
}
// 无效写法
let multiply = a,b=>{ //Unexpected token '=>'
return a,b
}
箭头函数也可以不使用大括号,但这样会改变函数的行为。使用大括号就说明包含“函数体”,可以在一个函数中包含多条语句,跟常规函数一样。如果不使用大括号,那么箭头函数就只能有一行代码,比如一个赋值操作,或者一个表达式。而且,省略大括号会隐式返回这行代码的值。
// 以下两种方法都有效,且返回相应的值
let double =(x)=>{
return x*2;
}
let triple = (x)=>3*x
// 可以赋值
let value = {}
let setName = (x)=>x.name = "Matt"
setName(value);
console.log(value.name); //Matt
// 无效写法
let multiply = (a,b)=>return a*b //Unexpected token 'return'
箭头函数虽然语法简介,但也有很多场合不适用。箭头函数不能使用argument
、super
、new,target
,也不能用作构造函数。此外,箭头函数也没有prototype
属性。
以上内容摘抄自红宝书第四版288页
特性
1. this指向
常规函数里的this
(即执行上下文)指向是动态的。这也是面试常考问题之一。动态的意思就是,this
的值取决于函数本身如何被调用。JavaScript
里调用常规函数通常有4种方式:
- 直接调用
this
指向全局对象(严格模式下是undefined)
function func(){
console.log(this);
}
func(); //Window对象
- 作为对象方法调用,
this
指向方法所属对象
let obj = {
method(){
console.log(this);
}
}
obj.method(); //{method: ƒ}
- 动态改变执行上下文的方式调用,即通过
.call
和.apply
,this
指向第一个参数代表的上下文对象
function fun(){
console.log(this);
}
let obj = {value:"Mgd"};
fun.call(obj) //{value: "Mgd"}
fun.apply(obj) //{value: "Mgd"}
- 作为构造函数调用。
this
指向通过new
关键字创建的实例
function Func() {
console.log(this);
}
let newFun = new Func()
newFun(); //Func {}
箭头函数的this
跟常规函数的规则完全不同。无论用什么方式、在哪里调用箭头函数,里面的this
永远是外层函数的this
。也就是说,箭头函数的this
是由词法决定的,它没有定义自己的执行上下文。
let obj = {
myFunc(items){
console.log(this)
let callback = ()=>{
console.log(this);
};
items.forEach(callback)
}
}
obj.myFunc([1,2,3])
在上面的代码中,myFunc()
就是箭头函数callback()
的外层函数,箭头函数里的this
等于外层函数的this
,也就是myFunc()
综上所述,由词法决定this
的指向,是箭头函数非常使用的特性之一。在方法里使用回调函数就很方便,this
指向很明确,不用去写替换this
和绑定this
的方法了。
2. 构造函数
常规函数可作为类的构造函数,用于创建实例
function Person(name){
this.name = name
}
let man = new Person("Mgd")
console.log(man instanceof Person); //true
let Person= (name)=>{
this.name = name
}
let man = new Person("Mgd") //Person is not a constructor
console.log(man instanceof Person);
我们知道箭头函数的this
指向由词法决定,没有自己的指向上下文,所以不能做构造函数,如果对箭头函数使用new
关键字,会报错。
3. arguments
常规函数中,arguments
是一个类数组对象,包含了函数在执行时接收到的参数列表
function fun(){
console.log(arguments);
}
fun(1,2)
function fun(){
let newFun = ()=>{
console.log(arguments);
}
newFun(3,4)
}
fun(1,2)
箭头函数中没有定义arguments
关键字,跟this
一样,也是由词法决定的,也就是会解析到外层函数的arguments
。
如果想获取箭头函数自己的参数对象,可以用ES6的剩余参数(…操作符)特性
function func(){
let arrwoFun = (...args)=>{
console.log(args); //[3, 4]
}
arrwoFun(3,4)
}
func(1,2)
4. 隐式返回值
对于常规函数,需要用return
语句返回一个值
function myFunction() {
return 42;
}
console.log(myFunction()); //42
如果没有return
语句,或者return
语句后面没有带表达式,常规函数会隐式返回undefine
function myEmptyFunction() {
42;
}
function myEmptyFunction2() {
42;
return;
}
console.log(myEmptyFunction()); //undefined
console.log(myEmptyFunction2()); //undefined
箭头函数除了可以用常规函数一样的方式返回值之外,还有一个独有的特性:如果箭头函数只包含一个表达式,那么就可以省略函数体的花括号和return
语句,并且这个表达式会被当作返回值
let increment = (num) => num + 1;
console.log(increment(41)); //42
5. 类的成员方法
通常用常规函数来定义类的成员方法
class Person {
constructor(name) {
this.name = name;
}
logName() {
console.log(this.name);
}
}
let person = new Person('Mgd');
但有时候我们需要把成员方法当成回调函数来用,比如setTimeout()
回调或者事件监听器。这个时候,如果要访问当前实例this
就会有问题了
比如,我们把logName()
方法当作 setTimeout()
的回调函数
setTimeout(person.logName.bind(person), 2000); //Mgd
每个方法都需要手动绑定this
执行上下文,很麻烦,可以使用箭头函数作为成员方法
箭头函数里的this
直接指向类的实例对象
class Person {
constructor(name) {
this.name= name;
}
logName = () => {
console.log(this.name);
}
}
let person = new Person('Mgd');
setTimeout(person.logName, 2000); //Mgd
现在person.logName
作为回调函数不再需要手动绑定this
执行上下文,它总是指向当前类的实例
特性总结
- 箭头函数的
this
指向永远是外层函数的this
- 由于
this
指向的问题,箭头函数不能做构造函数 - 箭头函数中没有定义
arguments
关键字,会解析到外层函数的arguments
,想获取箭头函数的参数可以用ES6的剩余参数(…操作符)特性 - 如果箭头函数只包含一个表达式,那么就可以省略函数体的花括号和
return
语句,并且这个表达式会被当作返回值 - 箭头函数作为类成员方法,箭头函数里的
this
直接指向类的实例对象,不需要手动绑定this
指向
参考文章:
红宝书第四版288页
知乎:ES6 箭头函数大起底:熟知这几个特点让你少踩很多坑