rico-c/RICO-BLOG

[译]你应该在何时避免使用箭头函数?

rico-c opened this issue · 1 comments

[译]你应该在何时避免使用箭头函数?

原文地址:https://medium.freecodecamp.org/when-and-why-you-should-use-es6-arrow-functions-and-when-you-shouldnt-3d851d7f0b26

原文日期:2018.6.6
译者:RicardoCao

箭头函数与ES5 function的差异

首先我们会发现箭头函数有非常多可以使用的句法,我们一起看看下面的例子:

1. 无参数

在没有参数的情况下,可以直接在 =>前放置一个圆括号()

() => 42

甚至连括号都不需要

_ => 42

2. 单个参数

在单个参数情况下,圆括号是可选的:

x => 42  || (x) => 42

3. 多个参数

在多个参数情况下,圆括号是必须的:

(x, y) => 42

4. 函数语句

在箭头函数中,如果代码语句多于一条,就需要使用花括号包裹函数语句 ,而一旦你使用了花括号,你也需要在箭头函数中使用return返回对应的返回值。

这里有一个使用箭头函数的例子:

var feedTheCat = (cat) => {
  if (cat === 'hungry') {
    return 'Feed the cat';
  } else {
    return 'Do not feed the cat';
  }
}

5. 输出对象

如果想返回一个对象,则需要用圆括号将对象包裹起来,这可以强制编译器解析圆括号中的内容并返回,而不是将花括号内当做函数语句。

x =>({ y: x })

匿名句法

我们需要注意到箭头函数是匿名的,这也意味着他们是没有函数名的,这也造成了一些问题:

1. 更难调试

当我们遇到BUG时,将不能根据函数名或发生异常的行数来定位异常函数的位置。

2. 无法调用自身

如果你需要在使用箭头函数中递归调用自身,那么你会发现这在箭头函数中是行不通的。

无绑定this

在ES6之前的函数this关键字指向会根据函数被调用的上下文环境决定。但是在箭头函数中,this在函数定义时绑定,这意味着箭头函数使用包裹箭头函数的外部代码中的this

举个栗子,我们看下面的setTimeout方法:

// ES5
var obj = {
  id: 42,
  counter: function counter() {
    setTimeout(function() {
      console.log(this.id);
    }.bind(this), 1000);
  }
};

在ES5的例子中,.bind(this)用来绑定this上下文,如果不使用bind的话,默认this将会是undefined

// ES6
var obj = {
  id: 42,
  counter: function counter() {
    setTimeout(() => {
      console.log(this.id);
    }, 1000);
  }
};

箭头函数无法绑定this关键字,所以它会自动向上一层作用域寻找this,并使用上一层的this

在何时应该避免使用箭头函数?

在一下几个情景你也许应该避免使用箭头函数:

1. 对象中的方法

当你调用cat.jumps,lives的数量并不会减少,这是因为this没有被绑定在cat对象上,而是使用父作用域的this

var cat = {
  lives: 9,
  jumps: () => {
    this.lives--;
  }
}

运行结果:
image

2. 动态上下文的回调函数

如果是在动态上下文的回调中,箭头函数是不适用的,下面看一下栗子:

var button = document.getElementById('press');
button.addEventListener('click', () => {
  this.classList.toggle('on');
});

这时点击按钮,会报错TypeError,这是因为this没有被绑定到按钮上。

3. 当箭头函数使你的代码可读性降低时

大量使用箭头函数,可能会对理解函数的含义造成障碍,这时可以考虑使用ES5函数增强可读性。

4. 用作构造函数时

箭头函数不可以作为构造函数,不可以使用new命令,否则会抛出一个错误。

Good