JavaScript 如何改变 this 指向
在前端开发中,很多新手刚接触JavaScript时,都会被一个叫“this指向”的问题绕得晕头转向——一会儿指这个,一会儿指那个,好像没个准数。其实this本身并不复杂,它就像一个“指向开关”,掌握了切换规则,就能轻松搞定。
this到底是啥?就像聚会里的“主角”
先举个生活化的例子:你和朋友聚会,你带了零食,朋友带了饮料,聚会的“主角”是谁,决定了大家的活动内容——主角是你的话,大家吃零食;主角是朋友的话,大家喝饮料。this就像这个“聚会主角”,它决定了代码里当前逻辑的“核心对象”,所有操作都围绕它展开。

平时写代码时,this的指向默认有个“基础规则”:在全局作用域里(比如直接写在script标签里的代码),this指向浏览器的window对象,就像聚会没指定主角时,默认以在场的所有人作为“共同核心”。比如你直接打印this,会输出整个window窗口的相关属性,就像聚会时默认聊和大家都有关的话题。
最常用的3种手动改指向方法,全是日常场景
默认指向偶尔会不符合需求,这时候就需要手动调整this的“主角身份”,最常用的有3种方法,每种都对应一个具体的开发场景:
call:一次性切换,还能带参数
假设你做了一个“学生信息展示”的功能,有个通用的showInfo函数,能显示人的姓名和年龄。如果直接调用,this会指向window,显示的是window的默认属性,没用。这时候用call就能把this切换成学生对象:
`javascript
function showInfo(school, grade) {
console.log(${this.name}今年${this.age}岁,在${school}读${grade}年级);
}
const student = {name: '小明', age: 10};
// 用call把this绑定到student,同时传入学年级参数
showInfo.call(student, '实验一小', '三年级');
// 输出:小明今年10岁,在实验一小读三年级
`
就像你带了通用的聚会小游戏,想让朋友当主角玩,就直接把游戏的主角换成朋友,还能加个“带饮料”的额外要求。
apply:参数直接传数组,适合批量数据
如果需要传递的参数很多,比如学生的多门成绩,用apply更方便,它的参数要求是数组形式:
`javascript
function showScores(...scores) {
console.log(${this.name}的成绩:${scores.join('、')});
}
const student = {name: '小红'};
// 用apply把this绑定到student,成绩以数组形式传入
showScores.apply(student, [90, 95, 88]);
// 输出:小红的成绩:90、95、88
`
好比你要给聚会带一堆零食,直接把整袋零食(数组)递给主角,不用一个个递参数。
bind:提前绑定,适合固定场景
如果想把this的指向固定下来,之后重复调用,不用每次都传参数,就用bind。比如你要做一个按钮,点击时弹出学生的信息,这时候用bind固定this,避免点击时this指向按钮:
`javascript
const student = {name: '小刚', age: 12};
function showName() {
console.log(this.name);
}
// 提前把this绑定到student,生成新函数
const showStudentName = showName.bind(student);
// 后续不管怎么调用,this都是student
showStudentName(); // 输出:小刚
// 模拟按钮点击
document.querySelector('button').addEventListener('click', showStudentName);
// 点击按钮会输出小刚,不会变成按钮的属性,完美解决场景问题
`
就像你提前和聚会的主角约定好,不管谁组织聚会,主角都是他,不会临时变卦。
避开常见坑:别让this“跑错场子”
新手最容易踩的坑,就是在定时器里用this。比如你想在3秒后输出学生的名字,写了这样的代码:
`javascript
const student = {name: '小丽'};
function showName() {
setTimeout(function() {
console.log(this.name);
}, 3000);
}
showName.call(student);
`
结果3秒后输出的是undefined,因为定时器里的函数是全局调用,this指向了window,window里没有name属性。这时候用刚才的bind就能解决,或者箭头函数(ES6新特性)也可以,箭头函数的this会继承外层作用域的指向,不用手动切换,更简单。
掌握了这几个规则,this指向就不再是难题,能帮你写出更灵活、更易维护的代码。