理解 this 在 JavaScript 中的动态绑定特性
掌握 this 在不同调用上下文中的指向规则
学会使用 call、apply 和 bind 显式控制 this 的值
了解箭头函数中 this 的词法作用域行为
能够准确预测和调试 this 相关的常见问题
this 基本概念在 JavaScript 中,this 是一个动态关键字,它始终指向当前执行上下文中的对象。与许多编程语言不同,JavaScript 的 this 不是在定义时确定的,而是在函数被调用时决定的。
const user = {
name: "开发者社区",
introduce() {
return `欢迎来到 ${this.name}!`;
}
};
console.log(user.introduce()); // 输出:欢迎来到 开发者社区!在这个例子中,this 指向 user 对象,因此可以访问其 name 属性。
this 的主要绑定规则当函数作为对象的方法被调用时,this 指向该对象。
const student = {
name: "李明",
grade: 10,
getInfo() {
console.log(`学生姓名:${this.name},年级:${this.grade}`);
}
};
student.getInfo(); // 输出:学生姓名:李明,年级:10规则:调用点左侧的对象决定了
this的值
当函数独立调用(不作为对象方法)时:
非严格模式:this 指向全局对象(浏览器中是 window,Node.js 中是 global)
严格模式:this 为 undefined
// 非严格模式示例
var globalName = "全局变量";
function sayHello() {
console.log(this.globalName); // 可能输出 "全局变量"
}
sayHello(); // 独立调用
// 严格模式示例
'use strict';
function strictFunc() {
console.log(this); // undefined
}
strictFunc();注意:在模块化或现代框架中,全局变量通常被避免,因此独立调用函数时
this往往无法访问预期属性。
通过 call()、apply() 或 bind() 手动指定 this 的值。
call 和 applyfunction checkEligibility() {
if (this.age >= 18) {
console.log(`${this.name} 可以考驾照`);
} else {
console.log(`${this.name} 还不能考驾照`);
}
}
const person1 = { name: "王伟", age: 20 };
const person2 = { name: "刘芳", age: 16 };
checkEligibility.call(person1); // 输出:王伟 可以考驾照
checkEligibility.call(person2); // 输出:刘芳 还不能考驾照call(obj, arg1, arg2, ...):参数逐个传递
apply(obj, [arg1, arg2, ...]):参数以数组形式传递
bindbind 返回一个新函数,其 this 被永久绑定:
const greet = function(greeting) {
return `${greeting}, 我是 ${this.name}`;
};
const user = { name: "张涛" };
const boundGreet = greet.bind(user);
console.log(boundGreet("你好")); // 输出:你好, 我是 张涛
bind常用于事件处理、回调函数等需要固定上下文的场景。
this箭头函数没有自己的 this,它会继承外层作用域的 this 值(词法作用域)。
const team = {
name: "前端组",
members: ["小李", "小王"],
// 普通函数:this 指向 team
listMembersNormal() {
this.members.forEach(function(member) {
// 这里的 this 指向全局对象(非严格模式)或 undefined(严格模式)
console.log(`${member} 属于 ${this.name}`); // this.name 为 undefined
});
},
// 箭头函数:this 继承自外层(即 team)
listMembersArrow() {
this.members.forEach((member) => {
// this 仍指向 team
console.log(`${member} 属于 ${this.name}`); // 正确输出
});
}
};
team.listMembersArrow();
// 输出:
// 小李 属于 前端组
// 小王 属于 前端组箭头函数适用于不需要动态
this的场景,如回调、工具函数等。
this当函数通过 new 调用时,this 指向新创建的实例对象。
function Product(name, price) {
this.name = name;
this.price = price;
this.describe = function() {
return `${this.name} 售价 ¥${this.price}`;
};
}
const laptop = new Product("笔记本电脑", 5999);
console.log(laptop.describe()); // 输出:笔记本电脑 售价 ¥5999在 ES6 类中同样适用:
class Book {
constructor(title, author) {
this.title = title;
this.author = author;
}
getInfo() {
return `"${this.title}" 作者:${this.author}`;
}
}
const book = new Book("深入浅出 Node.js", "朴灵");
console.log(book.getInfo()); // 输出:"深入浅出 Node.js" 作者:朴灵this 丢失const obj = {
value: 42,
getValue() {
return this.value;
}
};
const fn = obj.getValue; // 仅复制函数引用
console.log(fn()); // undefined(因为 this 指向全局)解决方案:使用 bind 绑定上下文
const safeFn = obj.getValue.bind(obj);
console.log(safeFn()); // 42this 问题const timer = {
seconds: 0,
start() {
setInterval(function() {
this.seconds++; // this 指向全局对象
console.log(this.seconds);
}, 1000);
}
};修复方式:
使用箭头函数:
start() {
setInterval(() => {
this.seconds++;
console.log(this.seconds);
}, 1000);
}或保存 this 引用:
start() {
const self = this;
setInterval(function() {
self.seconds++;
console.log(self.seconds);
}, 1000);
}this 绑定的优先级当多种规则同时存在时,JavaScript 按以下优先级确定 this:
new 绑定(最高)
显式绑定(call / apply / bind)
隐式绑定(对象方法调用)
默认绑定(最低)
function foo() {
console.log(this.name);
}
const obj1 = { name: "对象1", foo: foo };
const obj2 = { name: "对象2" };
// 显式绑定优先于隐式绑定
obj1.foo.call(obj2); // 输出:对象2this 的值由函数调用方式决定,而非定义位置
对象方法调用 → this 指向该对象(隐式绑定)
独立函数调用 → this 指向全局对象或 undefined(默认绑定)
使用 call/apply/bind 可强制指定 this(显式绑定)
箭头函数没有自己的 this,继承外层作用域(词法绑定)
构造函数中 this 指向新创建的实例
理解绑定优先级有助于解决复杂场景下的 this 问题
为什么在严格模式下,独立调用的函数中 this 是 undefined?这种设计有什么好处?
编写一个通用的 logThis 函数,无论以何种方式调用,都能正确打印当前 this 的值,并解释其在不同调用方式下的输出结果。