首先不得不承认,箭头函数是ES6中非常受欢迎的一个功能,它提出了一种新的书写方式来简洁的定义函数。
举例说明:
ES5:
function timesTwo(params) {
return params * 2;
}
timesTwo(4); //8
使用ES6箭头函数:
const timesTwo = params => params * 2;
timesTwo(4); //8
代码更简短,而且可以省略大括号和return语句(在没有代码块的情况下)。与ES5相比,为何箭头函数的表现方式可以有如此大的不同呢?
各种变量
你可能见过箭头函数有很多种的使用方式,比如:
- 没有参数
如果没有参数,可以在=>之前放置一个空括号
const a = () => 42
a() //42
实际上, 我们甚至不需要括号:
const a = _ => 42
a() //42
- 一个参数
在这种情况下,括号是可选的:
const a = x => 42 || const a = (x) => 42
a() || a(1) //42
- 多个参数
此时,必须加括号:
const a = (x, y) => 42
a(1, 2) //42
- 语句(而非表达式)
在最基本的形式中,表达式会产生一个值,而语句代表着一种待执行的行为,比如if else语句。使用箭头函数时,语句必须有大括号。而一旦使用了花括号,就必须添加return 关键字。
在箭头函数中使用if语句的例子:
var feedTheCat = (cat) => {
if (cat === 'hungry') {
return 'Feed the cat';
} else {
return 'Do not feed the cat';
}
}
- 代码块
如果你的代码在一个块中,就必须显式的使用return语句。
var addValues = (x, y) => {
return x + y
}
- 对象字面量
如果需要返回一个对象,就要使用()
包裹。这会迫使解释器去评估括号内的内容,能够正确的返回对象。
const obj = x =>({ y: x })
obj(1) //{y: 1}
匿名语法
箭头函数是匿名的,这会带来一些问题:
- 难以debug
出现错误时,无法追踪该方法名称或具体的执行行号(个人不是很认同,箭头函数相当于匿名函数,将其地址赋值给变量后不是一样的使用么)
- 没有自引用
如果你需要自引用(比如递归),使用箭头函数难以实现。
主要的优点: 不用显式绑定this
在函数表达式中,this是根据它被调用的上线文绑定到不同的值的,但是在箭头函数中,this是直接被绑定到词法作用域的。this 就是指向包含着箭头函数的这段代码。
举个栗子:
//ES5
var obj = {
id: 42,
counter: function counter() {
setTimeout(function() {
console.log(this.id);
}.bind(this), 1000);
}
};
在上段代码中,bind(this)
不能省略,否则this将指向window,从而this.id打印出undefined.
//ES6
var obj = {
id: 42,
counter: function counter() {
setTimeout(() => {
console.log(this.id);
}, 1000);
}
};
箭头函数不能绑定到this关键字,所以它会在词法上上升一个作用域,然后在定义的作用域中使用这个值。
何时不该使用箭头函数?
经过上边几个例子,应该也能意识到箭头函数并不能完全替代常规的函数。那么何时我们不该使用箭头函数呢?
- 对象方法
var cat = {
lives: 9,
jumps: () => {
this.lives--;
}
}
调用cat.jumps()
后,cat.lives
并不会减1。这是因为this就没有被绑定到这个对象上,而是从父级作用域继承了this
.
- 具有动态context的回调函数
当context需要动态改变的时候,箭头函数通常不是正确的选择。比如在一个事件句柄中:
var button = document.getElementById('press');
button.addEventListener('click', () => {
this.classList.toggle('on');
});
如果我们点击按钮,我们会得到一个TypeError。这是因为this不是绑定到按钮,而是绑定到了它的父级。
- 当使用箭头函数使你的代码可读性降低(难以知道这段代码将发生什么)的时候
何时使用箭头函数?
箭头函数最能发挥功力的场景就是需要this绑定到context,而非函数本身的时候。我还尤其喜欢在map
或者reduce
方法中使用箭头函数,这使得程序可读性更强。