this 指向分为两种情况,一种是普通函数中使用的 this,另外一种是箭头函数中的 this。

技巧:
普通函数:this 指向调用者。
箭头函数:这里就不用看谁是调用者了,而是看它定义时所在的环境(作用域)。箭头函数本身不存在 this,所以它的 this 指向上一层作用域所在的对象。

普通函数

场景1

  1. function sayHi() {
  2. console.log(this);
  3. }
  4. sayHi(); // window

这里的 this 指向 window,因为 sayHi 的调用者是 window,可是我没有看见有 window 啊,我们要知道 window 一般都是可以省略不写的,同等于 window.sayHi()

场景2

  1. const person = {
  2. sayHi: function () {
  3. console.log(this);
  4. },
  5. };
  6. person.sayHi(); // person

这里的 this 指向 personsayHi 是谁调用了? 很明显一看就知道是 person 。

场景3

  1. const person = {
  2. sayHi: function () {
  3. console.log(this);
  4. },
  5. };
  6. const xiaoming = person.sayHi;
  7. xiaoming(); // window

这里的 this 指向 window,首先是 person.sayHi 赋值给了 xiaoming,这个时候是还没调用的。那么 xiaoming 就是一个函数了,最后我们执行 window.xiaoming() ,调用者就是 window

场景4

  1. class Person {
  2. constructor() {}
  3. sayHi() {
  4. console.log(this);
  5. }
  6. }
  7. const xiaoming = new Person();
  8. xiaoming.age = 18;
  9. xiaoming.sayHi();

构造函数(类)中的 this 也是一样的,sayHi 的调用者是 xiaoming,所以 this 指向它。

场景5

  1. const div = document.querySelector('.content');
  2. div.onclick = function () {
  3. console.log(this);
  4. };
  5. div.onclick(); // 我们去页面点击元素,实际上就是执行的这行代码

dom 元素添加了点击事件,但是还没执行。当我们执行 div.onclick() 的时候,调用者就是 div ,所以 this 指向它。

箭头函数

场景1

  1. const sayHi = () => {
  2. console.log(this);
  3. };
  4. sayHi(); // window

sayHi 是一个箭头函数,本身没有 this,所以 sayHi this 指向上一层作用域所在的对象,也就是 window

场景2

  1. const person = {
  2. sayHi: () => {
  3. console.log(this);
  4. },
  5. };
  6. person.sayHi(); // window

sayHi 的上层作用域就是全局作用域,所在的对象是 window,所以 this 指向 window

场景3

  1. const person = {
  2. sayHi: function () {
  3. return {
  4. fn: () => {
  5. console.log(this);
  6. },
  7. };
  8. },
  9. };
  10. const xiaoming = person.sayHi();
  11. xiaoming.fn(); // person

this 在定义时是在 fn 函数作用域中,箭头函数本身不存在 this,所以它的 this 指向上一层作用域 sayHi 所在的对象 person,所以无论是谁调用了 fn this 始终指向 person

改变 this 指向

通过 call()apply()bind()可以改变 this 指向。

区别
主要是传参方式和执行方式不同:
applycall 的区别:接受参数的方式不一样。
bind:不立即执行。而 applycall 立即执行。

apply

  1. const Person = {
  2. name: 'xiaoming',
  3. };
  4. function fn(age, sex) {
  5. console.log(this); // {name: 'xiaoming'}
  6. }
  7. fn.apply(Person, [18, '男']);

call

  1. const Person = {
  2. name: 'xiaoming',
  3. };
  4. function fn(age, sex) {
  5. console.log(this); // {name: 'xiaoming'}
  6. }
  7. fn.call(Person, 18, '男');

bind

  1. const Person = {
  2. name: 'xiaoming',
  3. };
  4. function fn(age, sex) {
  5. console.log(this); // {name: 'xiaoming'}
  6. }
  7. const ex = fn.bind(Person, 18, '男');
  8. ex();