返回

箭头函数和This:巧用ES6构建更佳代码

前端

在函数式编程中,“this”是一个非常重要的概念,它代表了函数被调用的上下文。在普通函数中,“this”的值由函数被调用的方式决定,而在箭头函数中,“this”的值总是指向定义它的对象。

为了更好地理解这一点,我们来看一个简单的例子:

function Person(name) {
  this.name = name;
  this.greet = function() {
    console.log(`Hello, my name is ${this.name}`);
  };
}

const person = new Person("John Doe");
person.greet(); // Hello, my name is John Doe

在这个例子中,我们定义了一个Person类,并在它的构造函数中定义了一个greet方法。当我们创建一个Person对象并调用greet方法时,this的值指向该对象,因此我们可以访问对象属性name。

现在,我们使用箭头函数重写greet方法:

function Person(name) {
  this.name = name;
  this.greet = () => {
    console.log(`Hello, my name is ${this.name}`);
  };
}

const person = new Person("John Doe");
person.greet(); // TypeError: Cannot read property 'name' of undefined

当我们使用箭头函数重写greet方法后,this的值不再指向Person对象,而是指向window对象。因此,当我们调用greet方法时,this.name会返回undefined,并抛出TypeError异常。

造成这种情况的原因是箭头函数没有自己的this值,它会继承外层函数的this值。在我们的例子中,greet方法被定义在Person类的构造函数中,因此它的this值继承自Person对象。但是,当我们使用箭头函数重写greet方法后,箭头函数不再属于Person类,因此它的this值也不再继承自Person对象,而是继承自window对象。

为了解决这个问题,我们可以使用普通函数代替箭头函数,或者显式地绑定this值。

function Person(name) {
  this.name = name;
  this.greet = function() {
    console.log(`Hello, my name is ${this.name}`);
  }.bind(this);
}

const person = new Person("John Doe");
person.greet(); // Hello, my name is John Doe

在上面的例子中,我们使用bind方法显式地将this值绑定到Person对象,这样当我们调用greet方法时,this的值仍然指向Person对象,而不是window对象。

箭头函数非常适合于一些场景,例如事件处理程序和回调函数。但是,在使用箭头函数时,我们需要特别注意this值的变化,以避免出现意外错误。

何时使用普通函数,何时使用箭头函数?

  • 使用箭头函数的情况:
    • 当需要一个简洁的写法时
    • 当需要一个没有自己的this值的函数时
    • 当需要一个继承外层函数this值的函数时
  • 使用普通函数的情况:
    • 当需要一个有自己的this值的函数时
    • 当需要一个可以显式地绑定this值的函数时
    • 当需要一个可以在不同上下文下调用的函数时

总之,箭头函数是ES6中引入的新特性,它提供了更简洁的写法,但也有一些需要注意的陷阱。在使用箭头函数时,我们需要特别注意this值的变化,以避免出现意外错误。