JS this 的指向和改变

本文详细探讨了JavaScript中this的指向规律,包括在普通函数、立即执行函数、定时器函数、构造函数、对象方法、事件绑定及箭头函数等场景下的不同行为。同时,介绍了如何通过call、apply和bind方法来改变this的指向,为理解和运用JavaScript中的this提供了清晰的总结。
摘要由CSDN通过智能技术生成

js 中 this 的指向非常绕, 在此记录下自己实践时总结的规律, 方便复习。

this 指向


总结

this 具体的指向是分情况的, 不同情况有不同的规律

非箭头函数场合:

  • 普通函数、立即执行函数、定时器函数中 this 指向 window 对象
  • 构造函数、对象的方法中 this 指向当前实例对象
  • 事件绑定函数中 this 指向调用者

箭头函数场合:

  • 箭头函数声明在对象内, 那么箭头函数中的 this 就指向该对象声明时代码所在作用域中的 this
  • 箭头函数声明在实参处(既回调函数), 那么箭头函数中的 this 就指向宿主函数调用代码所在作用域中的 this


试验


1. 普通函数中 this 指向 window 对象

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>this 指向</title>
</head>
<body>
<script>
  function pointer() {
    console.dir(this)
  }
  pointer() // 结果: window对象
</script>
</body>
</html>

2. 立即执行函数中 this 指向 window 对象

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>this 指向</title>
</head>
<body>
<script>
  // 立即执行函数, 方式 1
  (function pointer() {
    console.dir(this)
  })()  // 结果: window对象

  // 立即执行函数, 方式 2
  ;(function pointer() {
    console.dir(this)
  }())  // 结果: window对象
</script>
</body>
</html>

3. 定时器函数中 this 指向 window 对象

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>this 指向</title>
</head>
<body>
<script>
  // 延迟执行一次
  window.setTimeout(function () {
    console.dir(this)
  }, 1000) // 结果: window对象

  // 延迟后间隔执行
  window.setInterval(function () {
    console.dir(this)
  }, 1000) // 结果: window对象
</script>
</body>
</html>

4. 构造函数中 this 指向当前实例对象

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>this 指向</title>
</head>
<body>
<script>
  function Person(name, age) {
    this.name = name
    this.age = age
    console.log(this)
  }

  new Person('ares5k', 27) // 结果:Person {name: "ares5k", age: 27}
  new Person('3s', 27) // 结果:Person {name: "3s", age: 27}
</script>
</body>
</html>

5. 对象的方法中 this 指向当前实例对象

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>this 指向</title>
</head>
<body>
<script>
  // 创建对象方式 1
  function Person(name, age) {
    this.name = name
    this.age = age
    this.pointer = function () {
      console.log(this)
    }
  }

  new Person('ares5k', 27).pointer() // 结果:Person {name: "ares5k", age: 27}
  new Person('3s', 27).pointer() // 结果:Person {name: "3s", age: 27}

  // 创建对象方式 2
  let obj = {
    sex: 0,
    pointer() {
      console.log(this)
    }
  }
  obj.pointer() // 结果:{sex: 0, pointer: ƒ}
</script>
</body>
</html>

6. 事件绑定函数中 this 指向调用者

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>this 指向</title>
</head>
<body>
<input type="button" value="点我">
<script>
  let btn = document.querySelector('input')
  btn.addEventListener('click', function () {
    console.dir(this)
  })
</script>
</body>
</html>

7. 箭头函数 - 对象方法中 this 指向该对象声明时代码所在作用域中的 this

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>this 指向</title>
</head>
<body>
<script>

  /*
   * 场景 1
   */

  // 箭头函数声明在对象中
  let obj1 = {
    fn: () => {
      console.log(this) // 结果: window 对象
    }
  }
  // obj1 对象声明代码所在作用域中的 this 是 window 对象
  console.log(this)

  // 调用箭头函数
  obj1.fn()

  /*
   * 场景 2
   */

  let obj2 = {
    fn: function () {

      // return 对象声明代码所在作用域中的 this 是 obj2 对象
      console.log(this)

      // 箭头函数声明在对象中
      return {
        innerFn: () => {
          console.log(this) // 结果: obj2 对象
        }
      }
    }
  }
  // 调用箭头函数
  obj2.fn().innerFn()

</script>
</body>
</html>

8. 箭头函数 - 实参(既回调函数)this 指向宿主函数调用代码所在作用域中的 this

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>this 指向</title>
</head>
<body>
<script>

  let obj1 = {
    fn: function () {

      // 宿主函数调用代码所在作用域, 该作用域中的 this是 obj1 对象
      console.log(this) // 结果: obj1 对象

      // 箭头函数声明在宿主函数的实参中
      window.setTimeout(() => {
        console.log(this) // 结果: obj1 对象
      })
    }
  }

  // 调用箭头函数
  obj1.fn()
</script>
</body>
</html>



改变 this 指向


箭头函数中的 this 指向无法修改。

修改 this 指向 - call


call 函数的第一个参数, 就是用来替换原 this 的, 后面的参数是可选的, 参数个数取决于目标函数的参数列表, 每个参数用逗号隔开, call 函数调用后, 会立即执行目标函数。

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>this 指向</title>
</head>
<body>
<script>
  // 声明一个对象
  let person = {
    name: 'ares5k',
    age: 27
  }

  // 声明一个函数
  function changePointer(param1, param2) {
    console.log(`参数列表: ${param1}${param2}`)
    console.log(`当前对象: ${this}`)
  }

  // 直接调用函数, this 指向 window
  changePointer('参数1', '参数2')
  // 使用 call 调用函数, 可以将 this 的指向修改
  changePointer.call(person, '参数1', '参数2')
</script>
</body>
</html>

修改 this 指向 - apply


apply 函数的第一个参数, 就是用来替换原 this 的, 第二个是可选数组, 数组长度取决于目标函数的参数列表, 每个参数都是数组中的一项, apply 函数调用后, 会立即执行目标函数。

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>this 指向</title>
</head>
<body>
<script>
  // 声明一个对象
  let person = {
    name: 'ares5k',
    age: 27
  }

  // 声明一个函数
  function changePointer(param1, param2) {
    console.log(`参数列表: ${param1}${param2}`)
    console.log(`当前对象: ${this}`)
  }

  // 直接调用函数, this 指向 window
  changePointer('参数1', '参数2')
  // 使用 apply 调用函数, 可以将 this 的指向修改
  changePointer.apply(person, ['参数1', '参数2'])
</script>
</body>
</html>

修改 this 指向 - bind


call 和 apply 都是调用后立即执行目标函数, 这样有个缺点就是没法当作回调函数使用。下面例子中, 虽然确实改变了 this 指向,但是本来想用 setTimeout 延迟 5 秒执行, 而因为使用了 call,所以变成了立即执行。
使用call和apply时setTimeout中无法实现回调功能

使用 bind 的方式来修改 this 指向就可以很好的解决这个问题, bind 调用后并不会立即执行目标函数, 而是会返回一个新的函数, 然后新函数内部的 this 就是修改后的对象。这种特点,使其非常适合修改回调函数中 this 的场合。

效果:
使用bind来修改回调函数中的this
代码:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>this 指向</title>
</head>
<body>
<div></div>
<script>
  let div = document.querySelector('div')

  // 声明一个对象
  let person = {
    name: 'ares5k',
    age: 27
  }

  // 声明一个函数
  function changePointer(param1, param2) {
    div.innerText = `参数列表: ${param1}${param2}\n当前对象: ${this}`
  }

  setTimeout(changePointer.bind(person, '参数1', '参数2'), 2000)
</script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值