关键字 this
指的是在函数调用时绑定到该函数的对象的 value。这意味着,当函数作为方法、独立函数或 构造函数 调用时,它的 value 是不同的。
当函数被调用时,它会在后台创建关键字 this
的实例,作为对包含该函数的对象的引用,从而可以从其作用域内访问与其一起定义的属性和方法。在某些方面,使用 this
类似于使用用 const
声明的变量。与常量一样,this
无法删除,并且其 value 无法重新赋值,但可以更改 this
关键字包含的对象的方法和属性。
全局绑定
在函数或对象的上下文之外,this
指的是 globalThis
属性,该属性是对大多数 JavaScript 环境中的全局对象的引用。在 Web 浏览器中运行的脚本上下文中,全局对象是 window
对象
this;
> Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, ...}
在 Node.js 中,globalThis
是 global
对象
$ node
Welcome to Node.js v20.10.0.
Type ".help" for more information.
> this
<ref *1> Object [global] {
...
}
在非严格模式下,this
也指独立函数内部的全局对象,因为父 Window
是有效“拥有”这些函数的对象。
function myFunction() {
console.log( this );
}
myFunction();
> Window {...}
(function() {
console.log( this );
}());
> Window {...}
当使用严格模式时,this
在独立函数内部的值为 undefined
(function() {
"use strict";
console.log( this );
}());
> undefined
在引入严格模式之前,this
的 null
或 undefined
值将被替换为对全局对象的引用。由于这种遗留行为,您有时可能会看到全局绑定被称为“默认绑定”。
隐式绑定
当函数作为对象的方法调用时,该方法内部的 this
实例指的是包含该方法的对象,从而可以访问与其并列的方法和属性
let myObject = {
myValue: "This is my string.",
myMethod() {
console.log( this.myValue );
}
};
myObject.myMethod();
> "This is my string."
this
的 value 看起来可能取决于函数及其封闭对象的定义方式。实际上,this
的 value 的上下文是当前的执行上下文。在本例中,执行上下文是 myObject
对象正在调用 myMethod
方法,因此 myObject
是 this
的 value。在前面的示例上下文中,这似乎是一个技术细节,但对于 this
的更高级用法,这是一个需要牢记的重要区别。
通常,以不期望周围代码具有任何特定结构的方式使用 this
。此规则的例外是 ES5 箭头函数。
箭头函数中的 this
在 箭头函数 中,this
解析为 词法封闭环境 中的绑定。这意味着箭头函数中的 this
指的是该函数最近的封闭上下文中 this
的 value
let myObject = {
myMethod() { console.log( this ); },
myArrowFunction: () => console.log( this ),
myEnclosingMethod: function () {
this.myArrowFunction = () => { console.log(this) };
}
};
myObject.myMethod();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }
myObject.myArrowFunction();
> Window {...}
在前面的示例中,myObject.myMethod()
将 myObject
记录为“拥有”该方法的对象,但 myObject.myArrowFunction()
返回 globalThis
(或 undefined
),因为箭头函数内部的 this
实例指的是最高的封闭作用域。
在以下示例中,myEnclosingMethod
在对象执行时,在该对象上创建一个箭头函数。箭头函数内部的 this
实例现在指的是封闭环境内部 this
的 value,即包含该箭头函数的方法。由于 myEnclosingMethod
内部的 this
的 value 指的是 myObject
,因此在您定义箭头函数后,箭头函数内部的 this
也指的是 myObject
let myObject = {
myMethod() { console.log( this ); },
myEnclosingMethod: function () {
this.myArrowFunction = () => { console.log(this) };
}
};
myObject.myEnclosingMethod();
myObject.myArrowFunction();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }
显式绑定
隐式绑定处理了使用 this
的大多数用例。但是,您有时可能需要 this
的 value 来表示特定的执行上下文,而不是假定的上下文。一个说明性的(如果有点过时)示例是在 setTimeout
的回调函数中使用 this
,因为此回调具有唯一的执行上下文
var myObject = {
myString: "This is my string.",
myMethod() {
console.log( this.myString );
}
};
myObject.myMethod();
> "This is my string."
setTimeout( myObject.myMethod, 100 );
> undefined
尽管 setTimeout
的这个特定缺点后来已通过其他功能得到解决,但先前已通过在预期上下文的作用域内创建对 this
的 value 的显式引用来解决类似的“丢失”this
问题。您有时可能会在旧代码库中看到使用 that
、self
或 _this
等标识符将 this
分配给变量的实例。这些是包含传递的 this
value 的变量的常用标识符约定。
当您使用 call()
、bind()
或 apply()
方法调用函数时,this
显式引用被调用的对象
let myFunction = function() {
console.log( this.myValue );
}
let myObject = {
"myValue" : "This is my string."
};
myFunction.call( myObject );
> "This is my string."
var myObject = {
myString: "This is my string.",
myMethod() {
console.log( this.myString );
}
};
setTimeout( myObject.myMethod.bind( myObject ), 100 );
> "This is my string."
显式绑定会覆盖隐式绑定提供的 this
value。
let myObject = {
"myValue" : "This string sits alongside myMethod.",
myMethod() {
console.log( this.myValue );
}
};
let myOtherObject = {
"myValue" : "This is a string in another object entirely.",
};
myObject.myMethod.call( myOtherObject );
> "This is a string in another object entirely."
如果以某种方式调用函数,将 this
的 value 设置为 undefined
或 null
,则在非严格模式下,该 value 将被 globalThis
替换
let myFunction = function() {
console.log( this );
}
myFunction.call( null );
> Window {...}
同样,如果以某种方式调用函数,使 this
具有原始 value,则在非严格模式下,该 value 将被替换为原始 value 的包装器对象
let myFunction = function() {
console.log( this );
}
let myNumber = 10;
myFunction.call( myNumber );
> Number { 10 }
在严格模式下,传递的 this
value 不会以任何方式强制转换为对象,即使它是原始值、null
或 undefined
value 也是如此
"use strict";
let myFunction = function() {
console.log( this );
}
let myNumber = 10;
myFunction.call( myNumber );
> 10
myFunction.call( null );
> null
new
绑定
当使用 new
关键字将类用作构造函数时,this
指的是新创建的实例
class MyClass {
myString;
constructor() {
this.myString = "My string.";
}
logThis() {
console.log( this );
}
}
const thisClass = new MyClass();
thisClass.logThis();
> Object { myString: "My string." }
同样,使用 new
调用的构造函数内部的 this
的 value 指的是正在创建的对象
function MyFunction() {
this.myString = "My string.";
this.logThis = function() {
console.log( this );
}
}
const myObject = new MyFunction();
myObject.logThis();
> Object { myString: "My string.", logThis: logThis() }
事件处理程序绑定
在事件处理程序的上下文中,this
的 value 引用调用它的对象。在事件处理程序的回调函数内部,这意味着 this
引用与处理程序关联的元素
let button = document.querySelector( "button" );
button.addEventListener( "click", function( event ) { console.log( this ); } );
当用户与上一个代码段中的 button
交互时,结果是包含 <button>
本身的元素对象
> Button {}
当箭头函数用作事件监听器回调时,this
的 value 再次由最近的封闭执行上下文提供。在顶层,这意味着事件处理程序回调函数内部的 this
是 globalThis
let button = document.querySelector( "button" );
button.addEventListener( "click", ( event ) => { console.log( this ); } );
> undefined
与任何其他对象一样,当您使用 call()
、bind()
或 apply()
方法来引用事件监听器的回调函数时,this
显式引用该对象
let button = document.querySelector( "button" );
let myObject = {
"myValue" : true
};
function handleClick() {
console.log( this );
}
button.addEventListener( "click", handleClick.bind( myObject ) );
> Object { myValue: true }
检查您的理解情况
对于在 Web 浏览器中运行的脚本,当在函数或对象的上下文之外使用 this
时,this
指的是哪个全局对象?
window
对象browser
对象undefined
对象