this指向问题

687 阅读3分钟

本文档已更新于 【前端橘子君】 【Github】

特别牢记

this的指向不是在函数定义时确定的,而是在函数调用时确定
this默认情况下指向window,严格模式下为undefined

隐式绑定

即this指向距离其最近的调用者

// this的隐式绑定
function fn() {
  console.log(this);
}

var obj = {
  name: '橘子君',
  fn: function () {
    console.log(this);
  }
}

fn(); // 输出:window
obj.fn(); // 输出:{name: "橘子君", fn: ƒ}

用大白话来说,所谓的最近的调用者就函数前面最近的一个对象。

在上述代码中:

  • obj.fn():距离函数 fn 最近的一个调用者是obj,所以最终输出{name: "橘子君", fn: ƒ}
  • fn():函数fn没有最近的调用者,所以会指向全局window,即本文最开始说的,默认情况下指向window
  • fn()fn() 也可以理解为window.fn(),其最近的一个调用者就是全局的 window

显式绑定(强制修改)

在JS中,有一些函数可以强制修改this的指向,如call, apply, bind等

1、call, apply, bind 中的this会指向传入的第一个参数
2、如果这些函数调用时没有传入参数,则指向默认对象(windowundefined)

// 显式绑定
function sum() {
  console.log(this)
}
var obj = {
  name: '橘子君'
}

sum.call(obj) // {name: "橘子君", fn: ƒ}
sum.apply() // window
sum.bind(obj)() // {name: "橘子君", fn: ƒ}

构造函数中的this

// 构造函数的this
function Fn () {
  this.name = '橘子君';
  console.log(this);
}

// 返回一个对象类型
function Fn2 () {
  this.name = '橘子君';
  return { name: '小橘子' }
}

// 返回一个基本类型
function Fn3 () {
  this.name = '橘子君';
  return 123;
}

new Fn() // 输出:Fn {name: "橘子君"}

console.log(new Fn()) // 输出:Fn {name: "橘子君"}
console.log(new Fn2()) // 输出:{name: "小橘子"}
console.log(new Fn3()) // 输出:Fn3 {name: "橘子君"}

结论:

构造函数中的this指向该函数创建的实例对象

拓展知识(new相关)

  • 1、如果该构造函数返回一个对象类型(如Object,Array,Function,Symbol, null 除外),则通过new关键字创建的实例指向其返回值
  • 2、否则返回该构造函数创建的实例对象

箭头函数中的this

箭头函数中的this是一种特别的情况,因为箭头函数本身并不存在this,其this是由其父级作用域继承而来

function fn () {
  return () => console.log(this)
}

var obj = {
  name: '橘子君',
  fn: function () {
    return () => console.log(this)
  }
}

fn()() // 输出:window
obj.fn()() // 输出:{name: "橘子君", fn: ƒ}

从上述代码来理解箭头函数中的this由其父级作用域继承而来这句话

this隐式绑定中我们知道:

  • fn()中的this指向全局的window,而箭头函数继承自父级(即fn),所以箭头函数中的this等于fn()中的this,即全局window
  • 同理,obj.fn()中的this指向对象obj,所以obj.fn()()中的this指向obj

注意事项:箭头函数中的this无法通过bind、call、apply进行修改

立即执行函数中的this

立即执行函数中的this就一句话:永远指向全局window

(function () {
  console.log(this) // 输出window
})()

更多相关文档,请见:

线上地址 【前端橘子君】

GitHub仓库【前端橘子君】