本文深入解析JavaScript中this关键字的指向规则,通过具体代码示例说明在事件处理函数中this指向DOM元素而非对象本身的常见错误。文章详细讲解了通过自由变量、ES6箭头函数以及bind方法绑定上下文三种解决方案,帮助开发者理解并避免this指向陷阱。
JavaScript this指向问题概述
长期以来,许多开发者对JavaScript中的this关键字感到困惑,其指向往往难以捉摸。今天,笔者对此有了清晰的认识,特此整理记录,以助他人解惑。
首先,我们来看一个具体的代码示例:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>this的使用</title>
<script type="text/javascript">
var Car,tesla;
Car=function () {
this.start=function(){
console.log('car started');
};
this.turnKye=function () {
var carKey=document.getElementById('car_key');
carKey.onclick=function () {
this.start();
};
}
return this;
}
tesla=new Car();
tesla.turnKye();
</script>
</head>
<body>
<input type="button" id="car_key" value="test" />
</body>
</html>
常见错误:事件处理中的this指向
乍看之下,这段代码逻辑通顺,但由于对this机制理解不足,最终会导致运行错误。我们在元素car_key上绑定了click事件,直觉上认为在Car类的turnKey方法内部绑定click事件,该事件处理函数就能访问到Car实例的this上下文。这种思路看似合理,但实际上无法按预期工作。
在JavaScript中,this关键字始终指向当前正在执行代码的作用域的所有者。
请仔细体会上述原则。正如我们所知,函数调用会创建新的作用域。当onclick事件被触发时,事件处理函数作为一个独立函数被调用,此时this指向的是触发事件的DOM元素,而非Car类的实例。
解决方案一:使用自由变量
那么,如何修正这一问题使其正常工作呢?一种常见的做法是将外层的this赋值给一个局部自由变量(如that、_this、self或me等,这在许多前端框架中十分常见),从而规避作用域变化带来的问题。以下是使用局部变量重写后的代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>this的使用</title>
</head>
<body>
<input type="button" id="car_key" value="test" />
<script type="text/javascript">
var Car,tesla;
Car=function () {
this.start=function(){
console.log('car started');
};
this.turnKye=function () {
var that=this;
var carKey=document.getElementById('car_key');
carKey.onclick=function () {
that.start();
};
}
return this;
}
tesla=new Car();
tesla.turnKye();
</script>
</body>
</html>
由于that是一个自由变量,它引用了外层函数的this值。因此,当onclick事件触发时,不会重新定义that,从而能够正确访问Car实例的方法。
解决方案二:ES6箭头函数
如果你熟悉ES6语法,可以使用箭头函数(胖箭头符号),这种方式更加简洁且语义清晰,代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>this的使用</title>
</head>
<body>
<input type="button" id="car_key" value="test" />
<script type="text/javascript">
var Car,tesla;
Car=function () {
this.start=function(){
console.log('car started');
};
this.turnKye=function () {
//var that=this;
var carKey=document.getElementById('car_key');
//carKey.onclick=function () {
// that.start();
//};
carKey.onclick=()=>this.start();
}
return this;
}
tesla=new Car();
tesla.turnKye();
</script>
</body>
</html>
解决方案三:使用bind方法
此外,我们还可以使用函数的bind方法来显式绑定上下文,具体实现如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>this的使用</title>
</head>
<body>
<input type="button" id="car_key" value="test" />
<script type="text/javascript">
var Car,tesla;
Car=function () {
this.start=function(){
console.log('car started');
};
var click=function(){
this.start();
}
this.turnKye=function () {
//var that=this;
var carKey=document.getElementById('car_key');
carKey.onclick=click.bind(this);
}
return this;
}
tesla=new Car();
tesla.turnKye();
</script>
</body>
</html>
这些技巧在早期学习React等框架时,处理事件绑定经常遇到。当时可能只是机械地记忆了写法,而未深究原理。如今理清了this的指向机制,希望能帮助到同样遇到此类困惑的开发者。