我们来看看this调用的几种情况,或者说,应该注意的几种情况
1. 全局上下文
在全局执行环境中(即不在任何函数内部),this 指向全局对象:
- 在浏览器中,
this指向window对象。 - 在 Node.js 环境中,
this指向global对象。 - 在严格模式 (
'use strict') 下,this将是undefined。
console.log(this); // 浏览器中:Window {...}
2. 函数调用
当一个函数被直接调用时(即不通过对象或构造函数调用),this 在非严格模式下指向全局对象,在严格模式下为 undefined。
function foo() {
console.log(this);
}
foo(); // 非严格模式下:Window {...};严格模式下:undefined
3. 方法调用
当函数作为对象的方法调用时,this 指向调用该方法的对象。
const obj = {
method: function() {
console.log(this);
}
};
obj.method(); // 输出 obj
4. 构造函数调用
当使用 new 关键字调用函数时,它被视为构造函数,此时 this 指向新创建的对象实例。
function Constructor() {
this.value = 'constructed';
}
const instance = new Constructor();
console.log(instance.value); // 'constructed'
5. call, apply, 和 bind
这些方法允许显式设置 this 的值:
call和apply立即调用函数,并将第一个参数作为this值传递给函数。bind返回一个新的函数,该函数的this值被永久绑定到传入的第一个参数。
function greet(greeting) {
console.log(`${greeting}, ${this.name}`);
}
const person = { name: 'Alice' };
greet.call(person, 'Hello'); // Hello, Alice
greet.apply(person, ['Hi']); // Hi, Alice
const greetPerson = greet.bind(person);
greetPerson('Hey'); // Hey, Alice
6. 箭头函数
箭头函数没有自己的 this 绑定,而是继承自外层作用域(词法作用域)。
const obj = {
name: 'Bob',
greet: () => {
console.log(`Hello, ${this.name}`); // this 指向全局对象或 undefined (严格模式)
}
};
obj.greet(); // Hello, undefined (严格模式)
// 使用普通函数可以正确获取 this
const obj2 = {
name: 'Charlie',
greet: function() {
console.log(`Hello, ${this.name}`); // this 指向 obj2
}
};
obj2.greet(); // Hello, Charlie
ok同学们这里思考一个问题,继承自外层,那么外层是指什么意思,如果不是很懂的话,我们来看这两行代码
const obj = {
name: 'Bob',
greet: (() => {
console.log(`Hello, ${this.name}`); // this 指向全局对象或 undefined (严格模式)
})()
};
解释:
-
箭头函数与
this:- 箭头函数没有自己的
this绑定,而是继承自外层作用域(词法作用域)。这意味着在箭头函数内部,this将指向定义该函数时所在的上下文,而不是调用时的上下文。
- 箭头函数没有自己的
-
立即执行函数表达式 (IIFE):
- 这行代码中,箭头函数是一个立即执行的函数表达式(IIFE),并且它在对象字面量内部被定义和调用。
- 由于它是立即执行的,因此它会在定义时立即运行,而不会等待
obj.greet被调用。
-
this的值:- 在这个 IIFE 中,
this的值取决于外部作用域。如果这段代码是在全局作用域中执行的,那么this将指向全局对象(浏览器中的window或 Node.js 中的global)。如果是在严格模式下,则this为undefined。
- 在这个 IIFE 中,
- 如果这段代码在非严格模式下的全局作用域中执行,
this将指向全局对象,因此this.name可能是undefined(除非全局作用域中有一个名为name的变量)。 - 如果是在严格模式下,
this将是undefined,因此this.name也将是undefined。
示例输出:
假设这段代码在严格模式下运行:
'use strict';
const obj = {
name: 'Bob',
greet: (() => {
console.log(`Hello, ${this.name}`); // 输出:Hello, undefined
})()
};
使用普通方法:
const obj = {
name: 'Bob',
greet() {
console.log(`Hello, ${this.name}`); // 输出:Hello, Bob
}
};
obj.greet();
使用函数表达式:
const obj = {
name: 'Bob',
greet: function() {
console.log(`Hello, ${this.name}`); // 输出:Hello, Bob
}
};
obj.greet();
使用箭头函数但不立即执行:
如果您坚持使用箭头函数,可以将其定义为对象的方法,但不要立即执行:
const obj = {
name: 'Bob',
greet: () => {
console.log(`Hello, ${this.name}`); // 注意:这里的 this 不是指向 obj
}
};
obj.greet(); // 输出:Hello, undefined (因为箭头函数的 this 指向定义时的上下文)
要让箭头函数正确引用 obj,可以将 obj 显式传递给箭头函数:
const obj = {
name: 'Bob',
greet: (() => {
const self = obj;
return () => console.log(`Hello, ${self.name}`);
})()
};
obj.greet(); // 输出:Hello, Bob
所以看到这里大家应该知道了这个外层是什么意思,意思就是外层的词法作用域,也就是花括号{},ok我们继续下一步
7. 事件处理程序
在 DOM 事件处理程序中,this 通常指向触发事件的元素。
<button id="myButton">Click me</button>
<script>
document.getElementById('myButton').addEventListener('click', function() {
console.log(this); // <button> element
});
</script>
8. 立即执行函数表达式 (IIFE)
在 IIFE 中,this 指向全局对象(非严格模式)或 undefined(严格模式)。
(function() {
'use strict';
console.log(this); // undefined
})();
this 的值依赖于函数的调用方式。通过使用 call、apply、bind 可以显式控制 this 的值,而在使用箭头函数时要注意它们不会创建自己的 this 上下文。