this 关键字
2025/8/24大约 5 分钟
this 关键字
this
是JavaScript中的一个特殊关键字,它指向函数执行时的上下文对象。理解 this
的绑定规则是掌握JavaScript的关键之一。
全局上下文中的 this
在全局上下文中,this
指向全局对象:
// 在浏览器中
console.log(this === window); // true
// 在Node.js中
// console.log(this === global); // true
// 全局变量是全局对象的属性
var globalVar = "全局变量";
console.log(this.globalVar); // "全局变量"
函数上下文中的 this
函数中的 this
的值取决于函数的调用方式,而非定义方式:
普通函数调用
在普通函数调用中,this
指向全局对象(非严格模式)或 undefined
(严格模式):
function myFunction() {
console.log(this); // 在浏览器中输出window对象
}
myFunction();
function myStrictFunction() {
'use strict';
console.log(this); // 输出undefined
}
myStrictFunction();
方法调用
当函数作为对象的方法调用时,this
指向调用该方法的对象:
var person = {
name: "John",
greet: function() {
return "Hello, my name is " + this.name + ".";
}
};
console.log(person.greet()); // "Hello, my name is John."
// 方法赋值给变量后调用
var greet = person.greet;
console.log(greet()); // "Hello, my name is undefined." (非严格模式)
构造函数调用
当函数作为构造函数使用 new
关键字调用时,this
指向新创建的实例:
function Person(name) {
this.name = name;
}
var john = new Person("John");
console.log(john.name); // "John"
call、apply 和 bind 方法
这些方法可以显式设置函数执行时的 this
值:
function greet(message) {
return message + ", " + this.name + "!";
}
var person = { name: "John" };
// call 方法
console.log(greet.call(person, "Hello")); // "Hello, John!"
// apply 方法 (参数以数组形式传递)
console.log(greet.apply(person, ["Hi"])); // "Hi, John!"
// bind 方法 (创建新函数)
var greetPerson = greet.bind(person);
console.log(greetPerson("Hey")); // "Hey, John!"
隐式绑定与显式绑定
- 隐式绑定:当函数被对象调用时,this隐式绑定到该对象
- 显式绑定:使用call、apply、bind方法强制绑定this的值
// 隐式绑定
var obj = {
name: "Object",
sayName: function() {
console.log(this.name);
}
};
\obj.sayName(); // 输出: "Object"
// 显式绑定
function sayName() {
console.log(this.name);
}
var anotherObj = { name: "Another Object" };
sayName.call(anotherObj); // 输出: "Another Object"
this 的常见问题
回调函数中的 this
在回调函数中,this
通常会丢失原始上下文,指向全局对象或undefined:
var person = {
name: "John",
greet: function() {
setTimeout(function() {
// 这里的this指向全局对象,而不是person
console.log("Hello, my name is " + this.name + "."); // "Hello, my name is undefined."
}, 1000);
}
};
// 解决方案1: 使用that变量
var person1 = {
name: "John",
greet: function() {
var that = this;
setTimeout(function() {
console.log("Hello, my name is " + that.name + "."); // "Hello, my name is John."
}, 1000);
}
};
// 解决方案2: 使用bind方法
var person2 = {
name: "John",
greet: function() {
setTimeout(function() {
console.log("Hello, my name is " + this.name + "."); // "Hello, my name is John."
}.bind(this), 1000);
}
};
嵌套函数中的 this
在嵌套函数中,内部函数的 this
不会继承外部函数的 this
:
var obj = {
name: "Object",
outer: function() {
console.log(this.name); // "Object"
function inner() {
console.log(this.name); // undefined (非严格模式下指向全局对象)
}
inner();
}
};
obj.outer();
// 解决方案: 使用that变量
var obj2 = {
name: "Object 2",
outer: function() {
var that = this;
function inner() {
console.log(that.name); // "Object 2"
}
inner();
}
};
obj2.outer();
事件处理函数中的 this
在事件处理函数中,this
指向触发事件的元素:
// HTML: <button id="myButton">点击我</button>
var button = document.getElementById("myButton");
button.addEventListener("click", function() {
// this指向button元素
console.log(this.textContent); // "点击我"
});
函数作为参数传递时的 this
当函数作为参数传递给另一个函数时,this
通常会丢失原始上下文:
var person = {
name: "John",
greet: function() {
console.log("Hello, my name is " + this.name + ".");
}
};
function callGreet(greetFn) {
greetFn();
}
callGreet(person.greet); // "Hello, my name is undefined."
// 解决方案1: 使用bind
callGreet(person.greet.bind(person)); // "Hello, my name is John."
// 解决方案2: 使用匿名函数包装
callGreet(function() {
person.greet();
}); // "Hello, my name is John."
常见问题与解答
1. 什么是 this 的绑定优先级?
this 的绑定优先级从高到低为:
- 显式绑定 (call, apply, bind)
- 构造函数绑定 (new 关键字)
- 隐式绑定 (对象方法调用)
- 默认绑定 (全局对象或 undefined)
2. 如何在函数中永久绑定 this 的值?
可以使用 bind
方法创建一个永久绑定 this 值的新函数:
function sayName() {
console.log(this.name);
}
var obj = { name: "Bound Object" };
var boundSayName = sayName.bind(obj);
boundSayName(); // "Bound Object"
// 即使使用call或apply也无法改变绑定
boundSayName.call({ name: "Another Object" }); // 仍然输出: "Bound Object"
3. 什么是方法链,它如何影响 this?
方法链是指连续调用对象的多个方法,每个方法的返回值是下一个方法的调用对象:
var calculator = {
value: 0,
add: function(num) {
this.value += num;
return this; // 返回this以支持链式调用
},
multiply: function(num) {
this.value *= num;
return this;
},
getValue: function() {
return this.value;
}
};
var result = calculator.add(5).multiply(2).getValue();
console.log(result); // 10
4. 如何在回调函数中保持 this 的上下文?
可以使用以下方法:
- 使用
that = this
变量捕获 - 使用
bind
方法 - 使用匿名函数包装
5. 严格模式对 this 有什么影响?
在严格模式下:
- 普通函数调用中的 this 为 undefined,而非全局对象
- 不能在函数内部修改 this 的值(尝试这样做会抛出错误)
- 函数参数不会自动成为全局对象的属性
总结
this
的值取决于函数的调用方式,而非定义方式- 全局上下文中的
this
指向全局对象 - 方法调用中的
this
指向调用该方法的对象 - 构造函数调用中的
this
指向新创建的实例 - 可以使用
call
、apply
和bind
方法显式设置this
的值 - 事件处理函数中的
this
指向触发事件的元素 - 在回调函数和嵌套函数中,
this
可能会丢失原始上下文,需要特殊处理
理解 this
的绑定规则是掌握JavaScript的关键之一,它帮助我们编写更灵活和可维护的代码。