JavaScript系列——this

153 阅读3分钟

在前端开发中,函数的this老是让人摸不着头脑,列举常见的this出现的场景,方便大家记忆学习,以下例子都是在浏览器环境下

执行环境

全局上下文中,this的指向全局对象

console.log(this === window) // true(浏览器环境)

函数上下文中,this的值取决于函数的调用方式, 在严格模式下,如果进入执行环境时没有设置 this 的值,this 会保持为 undefined

类上下文this在 类 中的表现与在函数中类似,因为类本质上也是函数,注意:在类的构造函数中,this 是一个常规对象。类中所有非静态的方法都会被添加到 this 的原型中

使用场景

1.call/apply

this将绑定到call/apply的第一个参数,在非严格模式下使用 callapply 时,如果用作 this 的值不是对象,则会被尝试转换为对象, null 和 undefined 被转换为全局对象

const obj = { a: 1 }

function testFn (paramA, paramB) {
  console.log(this.a, paramA, paramB)
}

testFn.call(obj, 2, 3) // 1 2 3
testFn.apply(obj, [2, 3]) // 1 2 3

call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组

2.bind

this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的,而其余参数将作为新函数的参数(偏函数),供调用时使用

const obj = { a: 1 }

function testFn (paramA, paramB) {
  console.log(this.a, paramA, paramB)
}

const bundle = testFn.bind(obj, 2, 3)

bundle() // 1 2 3

3.箭头函数

在箭头函数中使用this值与封闭词法环境的this保持一致,全局环境中指向全局对象 备注:箭头函数没有自己的thisargumentssupernew.target

setTimeout(() => {
  console.log(this) // this指向为window
})

function Test () {
  this.a = 1

  setTimeout(() => {
    console.log(this.a) // this指向 Test
  })
}
const t = new Test()

4.作为对象的方法

this的值将指向调用方法的对象

const obj = {
 a: 1,
 getA () {
   console.log(this.a)
   return this.a
 }
}

obj.getA() // 1

5.原型链中的this

如果该方法存在于对象的原型链上,this的值将指向调用函数的对象

function Test () {
  this.a = 1
}

Test.prototype.getA = function () {
  console.log(this.a)
  return this.a
}

const t = new Test()

t.getA() // 1

6.getter与setter中的this

this的值将指向获取或者设置属性的对象

let a = {
  a: 1,

  get name () {
    return this.a
  }
}

Object.defineProperty(a, 'b', {
  get () {
    return this.a
  },

  set (val) {
    this.b = val
  }
})

7.作为构造函数

this的值指向正在构造的新对象

function Test () {
  this.a = 1
  console.log(this.a) // this指向 t
}
const t = new Test()

8.作为一个DOM事件处理函数

this的值指向currentTarget,注意区分currentTargettarget的区别,currentTarget是指向事件绑定的元素,target是事件触发的元素

// index.html文件
<button id="btn">click</button>
// js代码
const btnEle = document.querySelector('#btn')

function onClick (e) {
  console.log(e.currentTarget === this) // true
}
btnEle.addEventListener('click',onClick)

9.作为内联事件处理函数

this的值指向监听器所在的DOM元素,没有设置内部函数的 this,它指向 window 对象

// index.html
<button id="btn" onclick="onClick()">test</button>
// index.js
function onClick () {
   console.log(this) // window 没有设置内部函数的 this,所以它指向 global/window 对象
}

// this指向 button元素
<button onclick="alert(this.tagName.toLowerCase());"></button>

总结

绝大多数情况下,函数的调用方式决定了this的值(运行时绑定this的值),每次函数调用时,this的值也有可能不一样。当然了我们可以使用call/applybind指定函数的this值,而不需要考虑函数的调用方式