如何在回调函数内部访问正确的“this”?


在本教程中,我们将学习如何在回调函数内部访问正确的“this”。

“this”关键字

每个函数都包含一个称为 this 的关键字,也称为“上下文”,其值由函数的调用方式决定,而不是由其定义方式、时间或位置决定。与其他变量不同,它不受词法作用域的影响。与其他语言相比,JavaScript 在使用函数的“this”关键字时略有不同。在严格模式和非严格模式之间,还有一些其他的变化。

函数的调用方式通常决定“this”的值(运行时绑定)。它在每次调用函数时都可能改变,并且在其执行期间不能通过赋值来改变。对于函数的调用方式,bind() 方法可以设置此值,因为箭头函数没有自己的“this”绑定(它保留封闭词法上下文的“this”值)。

什么是回调函数?

从另一个函数接收参数的函数称为回调函数,通常在外部函数中稍后使用。外部函数接受回调函数的术语称为高阶函数。

回调函数拥有自己的一组方法和属性,因为在 JavaScript 中函数是对象。“this”属性在高阶函数中执行时分配给回调函数,完全取决于回调函数的创建方式,而不是其定义位置、方式或时间。

通过检查调用回调函数的高阶函数,我们可以确定回调函数内的“this”值。封闭函数的实际定义可能包含局部作用域属性,这是回调函数中 this 问题的主要原因。但是,由于回调函数的上下文会根据其调用方式动态变化,因此在通过回调函数内的“this”绑定访问该属性时,该属性不存在。

现在我们将学习在回调函数内部访问正确的“this”的方法。

使用“self”模式

创建一个名为 self 的变量,并为其赋予在声明函数的作用域中的 this 值,这是一个常见的模式。我们可以通过创建一个名为 self 的新变量(任何其他有效的变量名都可以)并为其赋予“this”的值来实现所需的行为。

示例

<html>
<body>
   <h2> 'this' Inside a Callback using the <i> 'self' pattern </i> </h2>
   <button onclick="myFunction()"> Click here </button>
   <div id="root" style="
      background-color: rgb(240, 248, 255);
      border: 1px solid gray;
      margin: 5px 0px;
      padding: 10px;
   ">
      Welcome to Tutorialspoint!
   </div>
   <script>
      const root = document.getElementById('root')
      function myFunction() {
         this.variable = 'I am this variable'
         const variable = 'I am a const variable'
         const self = this
         setTimeout(() => {
            root.innerHTML = this.variable + '<br/>'
            root.innerHTML += variable
         }, 1000)
      }
   </script>
</body>
</html>

使用箭头函数

ECMAScript 6 引入了 JavaScript 箭头函数。它们没有自己的绑定,并且是传统函数表达式的更简洁的替代方案。这确保了如果在箭头函数内引用 this,则会在作用域中将其作为常规变量进行搜索。

示例

<html>
<body>
   <h2> 'this' Inside a Callback using the <i> arrow function </i> </h2>
   <button onclick="myFunction('ABC')"> Click here </button>
   <div id="root" style="
      background-color: rgb(240, 248, 255);
      border: 1px solid gray;
      margin: 5px 0px;
      padding: 10px;
   ">
      Welcome to Tutorialspoint!
   </div>
   <script>
      const root = document.getElementById('root')
      function myFunction(name) {
         this.name = name
         let obj = {
            run: function(callback) {
               setTimeout(callback, 1000)
            },
         }
         obj.run(() => {
            root.innerHTML = this.name
         })
      }
   </script>
</body>
</html>

使用另一个变量存储“this”对象

对象链接到它,这通常是我们尝试在回调函数内部访问 this 时真正想要访问的内容。一种方法是在回调函数作用域之前创建一个变量并存储其值(尽管一些程序员可能不愿意这样做,因为它看起来很混乱)。

有些人称之为 that 或 self,但只要术语清晰,名称并不重要。此解决方法有效,因为该变量符合词法作用域要求,因此在回调函数内可用。您仍然可以访问回调函数的动态 this 绑定,这是此方法的额外好处。

示例

<html>
<body>
   <h2>
      'this' Inside a Callback using the
      <i> another variable to store the 'this' object </i>
   </h2>
   <button onclick="myFunction('XYZ')"> Click here </button>
   <div id="root" style="
      background-color: rgb(240, 248, 255);
      border: 1px solid gray;
      margin: 5px 0px;
      padding: 10px;
   ">
      Welcome to Tutorialspoint!
   </div>
   <script>
      const root = document.getElementById('root')
      function myFunction(name) {
         this.name = name
         let that = this
         let obj = {
            run: function(callback) {
               setTimeout(callback, 1000)
            },
         }
         obj.run(function() {
            root.innerHTML = this.name
         })
      }
   </script>
</body>
</html>

显式地将 this 绑定到对象

当我们定义回调函数时,我们可以声明我们希望 this 是什么。我们可以使用 bind() 方法设置“this”值,并确保无论函数如何或在何处调用或传递,它都将保持不变。

bind() 方法在每个函数中都可用,并创建一个新的函数,其“this”属性连接到给定的对象。返回的函数和原始函数之间的唯一区别是您可以完全控制“this”属性指向的内容。

示例

<html>
<body>
   <h2>
      'this' Inside a Callback using
      <i> explicitly binding this to an object </i>
   </h2>
   <button onclick="myFunction('Tutorialspoint')"> Click here </button>
   <div id="root" style="
      background-color: rgb(240, 248, 255);
      border: 1px solid gray;
      margin: 5px 0px;
      padding: 10px;
   ">
      Welcome to Tutorialspoint!
   </div>
   <script>
      const root = document.getElementById('root')
      function myFunction(name) {
         this.name = name
         let callbackFunction = function() {
            root.innerHTML = this.name
         }.bind(this)
         let obj = {
            run: function(callbackFunction) {
               setTimeout(callbackFunction, 1000)
            },
         }
         obj.run(callbackFunction)
      }
   </script>
</body>
</html>

更新于:2022-12-06

491 次浏览

启动你的职业生涯

完成课程获得认证

开始学习
广告