本文详细解析JavaScript中this关键字的六种绑定场景。涵盖纯函数、对象方法调用、new构造函数、内部函数闭包、call/apply显式绑定以及DOM事件绑定的具体表现。重点说明内部函数this丢失问题及解决方案,对比不同事件绑定方式下this指向的差异,帮助开发者掌握this的核心机制。
JavaScript this关键字概述
作为面向对象编程的核心关键字,深入理解并熟练运用this对于提升代码的健壮性与优雅程度具有决定性意义。鉴于JavaScript中的this行为与Java、C#等严格面向对象语言存在显著差异,其复杂性往往导致开发者产生困惑。
this关键字主要应用于以下场景: 1. 独立函数调用 2. 对象方法调用 3. 构造函数通过new实例化 4. 嵌套内部函数 5. 利用call或apply方法 6. 事件监听绑定
纯函数中的this指向
1. 独立函数调用
代码示例如下:
var name = 'this is window'; // 为window对象定义name属性
function getName(){
console.log(this); // 控制台输出: Window // this指向全局对象--window
console.log(this.name); // 控制台输出: this is window /
}
getName();
结果解析:在独立函数调用中,this默认指向全局对象,即window。
对象方法调用时的this
2. 对象方法调用
代码示例如下:
var name = 'this is window'; // 定义window的name属性,用于验证this.name的指向
var testObj = {
name:'this is testObj',
getName:function(){
console.log(this); // 控制台输出:testObj // this指向调用该方法的对象testObj
console.log(this.name); // 控制台输出: this is testObj
}
}
testObj.getName();
结果解析:当通过对象方法调用时,this指向实际调用该方法的对象。
构造函数中的this绑定
3. 使用new调用构造函数
代码示例如下:
function getObj(){
console.log(this); // 控制台输出: getObj{} // this指向新创建的getObj实例
}
new getObj();
结果解析:在new构造函数过程中,this指向新创建的实例对象。
内部函数中的this丢失问题
4. 内部函数
代码示例如下:
var name = "this is window"; // 定义window的name属性,用于验证this.name的指向
var testObj = {
name : "this is testObj",
getName:function(){
//var self = this; // 临时保存this引用
var handle = function(){
console.log(this); // 控制台输出: Window // this指向全局对象--window
console.log(this.name); // 控制台输出: this is window
//console.log(self); // 通过此方式可获取指向testObj的this
}
handle();
}
}
testObj.getName();
结果解析:内部函数中的this依然指向全局对象window。这通常被视为JavaScript语言的设计缺陷,因为开发者通常不希望内部函数this指向全局。常规解决方案是将this赋值给变量(如that或self)以保存上下文,如代码所示。
使用call和apply改变this指向
5. 使用call / apply
代码示例如下:
var name = 'this is window'; // 定义window的name属性,用于验证this.name的指向
var testObj1 = {
name : 'this is testObj1',
getName:function(){
console.log(this); // 控制台输出: testObj2 // this指向被绑定的testObj2对象
console.log(this.name); // 控制台输出: this is testObj2
}
}
var testObj2 = {
name: 'this is testObj2'
}
testObj1.getName.apply(testObj2);
testObj1.getName.call(testObj2);
注意:apply与call功能相似,区别在于第二个参数的传递形式: [1] call( thisArg [,arg1,arg2,… ] ); // 第二个参数为参数列表:arg1,arg2,... [2] apply(thisArg [,argArray] ); // 第二个参数为参数数组:argArray 结果解析:通过call或apply调用函数时,函数内部的this指向被绑定的指定对象。
事件绑定中的this指向差异
6. 事件绑定 事件处理函数中的this指向是最易引发混淆的环节,多数错误均由此产生。
代码示例如下:
// 在页面Element元素上进行绑定
<script type="text/javascript">
function btClick(){
console.log(this); // 控制台输出: Window // this指向全局对象--window
}
</script>
<body>
<button id="btn" onclick="btClick();" >点击</button>
</body>
代码示例如下:
// JavaScript中绑定方式(1)
<body>
<button id="btn">点击</button>
</body>
<script type="text/javascript">
function btClick(){
console.log(this); // 控制台输出:<button id="btn">点击</button> // this指向Element按钮对象
}
document.getElementById("btn").onclick = btClick;
document.getElementById("btn").onclick;
</script>
代码示例如下:
// JavaScript中绑定方式(2)
<body>
<button id="btn">点击</button>
</body>
<script type="text/javascript">
document.getElementById("btn").onclick = function(){
console.log(this); // 控制台输出:<button id="btn">点击</button> // this指向Element按钮对象
}
document.getElementById("btn").onclick;
</script>
代码示例如下:
// JavaScript中绑定方式(3)
<body>
<button id="btn">点击</button>
</body>
<script type="text/javascript">
function btClick(){
console.log(this);
}
document.getElementById("btn").addEventListener('click',btClick); // 控制台输出:<button id="btn">点击</button> // this指向Element按钮对象,将函数用作事件处理程序。
document.getElementById("btn").attachEvent('onclick',btClick); // IE浏览器使用,控制台输出: Window // this指向全局对象--window
</script>
结果解析:上述两种常用事件绑定方式中,在页面Element上直接进行事件绑定(onclick="btClick();")时,this指向全局对象;而在JavaScript代码中进行绑定时,除attachEvent绑定的事件外,this均指向触发事件的Element元素。