也谈箭头函数的 this 指向问题及相关

注:本文和 this(他喵的)究竟是什么 — 理解 JavaScript 中的 this、call、apply 和 bind一块儿食用更佳。

最近翻译了一篇关于 this 的文章,不少人评价不错,可是原文没有讲到箭头函数的 this,因此我来补充一篇文章来专门讲解。浏览器

箭头函数是 ES6 添加的新语法,基础知识就很少介绍了,下面咱们来说一讲箭头函数的 this 怎么指向。bash

问题起源

在以往的函数中,this 有各类各样的指向(隐式绑定,显示绑定,new 绑定, window 绑定......),虽然灵活方便,但因为不能在定义函数时而直到实际调用时才能知道 this 指向,很容易给开发者带来诸多困扰。闭包

假如咱们有下面这段代码(本文代码都是在浏览器下运行),app

function User() {
  this.name = 'John';

  setTimeout(function greet() {
    console.log(`Hello, my name is ${this.name}`); // Hello, my name is 
    console.log(this); // window
  }, 1000);
}

const user = new User();
复制代码

greet 里的 this 能够由上一篇文章的四个规则判断出来。对,由于没有显示绑定、隐式绑定或 new 绑定、因此直接得出结论 this 指向 window。但实际上咱们想把 this 指向 user 对象!函数

之前是怎么解决的呢?看下面的代码:post

1. 使用闭包ui

function User() {
  const self = this;
  this.name = 'John';

  setTimeout(function greet() {
    console.log(`Hello, my name is ${self.name}`); // Hello, my name is John
    console.log(self); // User {name: "John"}
  }, 1000);
}

const user = new User();
复制代码

2. 使用显示绑定 — bindthis

function User() {
  this.name = 'John';

  setTimeout(function greet() {
    console.log(`Hello, my name is ${this.name}`); // Hello, my name is John
    console.log(this); // User {name: "John"}
  }.bind(this)(), 1000);
}

const user = new User();
复制代码

3. 利用 setTimeout 的能够传更多参数的特性spa

其实第三种和第一种比较像,都用到了闭包。翻译

function User() {
  this.name = 'John';

  setTimeout(function greet(self) {
    console.log(`Hello, my name is ${self.name}`); // Hello, my name is John
    console.log(self); // User {name: "John"}
  }, 1000, this);
}

const user = new User();
复制代码

三种方法均可以解决问题,可是都要额外写冗余的代码来指定 this

如今,箭头函数(Arrow Function)正是 ES6 引入来解决这个问题的,它能够轻松地让 greet 函数保持 this 指向 user 对象。

箭头函数如何解决

下面是箭头函数版本:

function User() {
  this.name = 'John';

  setTimeout(() => {
    console.log(`Hello, my name is ${this.name}`); // Hello, my name is John
    console.log(this); // User {name: "John"}
  }, 1000);
}

const user = new User();
复制代码

完美,直接把普通函数改为箭头函数就能解决问题。

箭头函数在本身的做用域内不绑定 this,即没有本身的 this,若是要使用 this ,就会指向定义时所在的做用域的 this。在上面的代码中即指向 User 函数的 this,而 User 函数经过 new 绑定,因此 this 实际指向 user 对象。

若是上述代码在严格模式下运行会有影响吗?

function User() {
  this.name = 'John';

  setTimeout(() => {
    'use strict'
    console.log(`Hello, my name is ${this.name}`); // Hello, my name is John
    console.log(this); // User {name: "John"}
  }, 1000);
}

const user = new User();
复制代码

答案是没有影响。由于箭头函数没有本身的 this,它的 this 来自于 Userthis只要 Userthis 不变,箭头函数的 this 也保持不变

那么使用 bindcall 或者 apply 呢?

function User() {
  this.name = 'John';

  setTimeout((() => {
    console.log(`Hello, my name is ${this.name}`); // Hello, my name is John
    console.log(this); // User {name: "John"}
  }).bind('no body'), 1000);
}

const user = new User();
复制代码

答案仍是没有影响。由于箭头函数没有本身的 this,使用 bindcall 或者 apply 时,箭头函数会自动忽略掉 bind 的第一个参数,即 thisArg

总结:箭头函数在本身的做用域内没有本身的 this,若是要使用 this ,就会指向定义时所在的做用域的 this

欢迎在下方评论交流哦!

相关文章
相关标签/搜索