如何在回调函数内部访问正确的“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>