改变this指向的方法
文章目录
- 一、为什么要改变 this 的指向?
- 二、如何改变 this 的指向?
- 1. bind() -- 返回一个绑定了 this 的新函数
- 2. call()和apply() -- 立即调用函数并指定this
- 3. 箭头函数 -- 不绑定 this,继承外层作用域
- 4. 临时变量保存 this (旧写法)
- 三、各种方法的区别与对比
- 四、项目中实践
- 1. 表单校验中的回调(Vue/React 常见)
- 2. React Class 组件中绑定事件
- 3. Vue 2.x 汇总使用定时器或者第三方库回调
- 4. 数组方法中的回调函数
- 五、总结
一、为什么要改变 this 的指向?
在 JavaScript 中,this 是一个经常让初学者头疼的问题,尤其是在函数调用、事件处理、回调函数等场景中。this的指向经常“不按套路出牌”。因此,掌握并合理改变this的指向,对于写出高质量的 JavaScript 代码至关重要。
示例1: 回调函数中丢失 this
const person = {name: "HopeBearer",greet() {setTimeout(function() {console.log(`Hello, I am ${this.name}`)}, 1000)}
}person.greet() // => Hello, I am undefined
this 指向了 window,不是person,原因是在浏览器中,普通函数默认的this是window对象(在严格模式下是undefined),因此,this.name 实际上是 window.name,而浏览器环境中默认 window.name 是undefined。
示例2:事件处理函数中 this 指向DOM元素
const btn = document.querySelector('#btn')
const app = {text: 'Click me!',handleClick() {console.log(this.text)}
}
btn.addEventListener('click', app.handleClick); // => undefined
this 实际指向的是触发事件的 DOM 元素,而不是 app,原因是app.handleClick 是一个方法,它直接作为回调传给了addEventListener,在这种情况下,JavaScript 并不会保留 app 作为 this,而是将 this 设置为触发事件的 DOM 元素。
二、如何改变 this 的指向?
JavaScript 提供了多种方式来控制 this,包括:bind、call、apply、箭头函数、临时变量等。
1. bind() – 返回一个绑定了 this 的新函数
const boundFn = app.handleClick.bind(app)
btn.addEventListener('click', boundFn)
2. call()和apply() – 立即调用函数并指定this
function sayHello(age) {console.log(`Hello, I am ${this.name}, ${age} years old.`)
}const person = {name: 'Bob'
}
sayHello.call(person, 30) // 参数用逗号分隔
sayHello.apply(person, [30]) // 参数用数组
3. 箭头函数 – 不绑定 this,继承外层作用域
const person = {name: 'HopeBearer',greet() {setTimeout(() => {console.log(`Hello, I am ${this.name}`)}, 1000)}
}person.greet() // Hello, I am HopeBearer
4. 临时变量保存 this (旧写法)
const self = this;
setTimeout(function(){console.log(self.name)
}, 1000)
三、各种方法的区别与对比
方法 | 是否立即调用 | 是否返回新函数 | 是否永久绑定 | 是否继承作用域 | 使用场景 |
---|---|---|---|---|---|
call() | ✅ 是 | ❌ 否 | ❌ 否 | ❌ 否 | 临时调用函数,改变上下文 |
apply() | ✅ 是 | ❌ 否 | ❌ 否 | ❌ 否 | 参数为数组时调用函数 |
bind() | ❌ 否 | ✅ 是 | ✅ 是 | ❌ 否 | 创建新函数,延迟调用 |
箭头函数 | ✅ 自动 | ❌ 否 | ✅ 是(不可更改) | ✅ 是 | 回调函数、计时器、事件等保留 this |
临时变量法 | ❌ 否 | ❌ 否 | ✅ 是 | ✅ 是 | 老写法(可用箭头函数替代) |
四、项目中实践
1. 表单校验中的回调(Vue/React 常见)
form.validateField('username', function(isValid) {if(isValid) {this.submitForm()}
}).bind(this) // 显式绑定
2. React Class 组件中绑定事件
class MyComponent extends React.Component {constructor(props) {super(props);this.handleClick = this.handleClick.bind(this) // 提前绑定}handleClick(){console.log(this.props.title)}render() {return <button onClick={this.handleClick}>Click</button>}
}// React 函数组件可用箭头函数或 useCallback
3. Vue 2.x 汇总使用定时器或者第三方库回调
export default {methods: {loadData() {setTimeout(() => {this.fetchData(); // 箭头函数保留 this}, 1000);}}
}
4. 数组方法中的回调函数
const people = ['Alice', 'Bob'];
const greeter = {prefix: 'Hello',greetAll() {people.forEach(function(name) {console.log(`${this.prefix}, ${name}`);}.bind(this)); // 显式绑定 this}
};
greeter.greetAll();
五、总结
JavaScript 中的 this 是一个灵活而强大的机制,但也极易出错。掌握以下要点,能让你写出更可靠的代码:
-
call/apply 用于立即调用函数;
-
bind 用于返回一个永久绑定 this 的函数;
-
箭头函数则用于保留父作用域的 this,尤其适合回调;
-
在 Vue/React 项目中合理选择方式,避免 this 丢失带来的问题。