本文深入剖析JavaScript中this关键字在不同执行环境下的指向逻辑。从全局对象、构造函数、对象方法到嵌套函数,逐一解析this的绑定规则,并结合apply/call及原型继承场景说明上下文替换机制,帮助开发者准确掌握this的行为。
JavaScript this关键字概述
JavaScript 是一种脚本语言,因此被很多人认为是简单易学的。然而情况恰恰相反,JavaScript 支持函数式编程、闭包、基于原型的继承等高级功能。本文仅采撷其中的一例:JavaScript 中的 this 关键字,深入浅出的分析其在不同情况下的含义,形成这种情况的原因以及 Dojo 等 JavaScript 工具中提供的绑定 this 的方法。可以这样说,正确掌握了 JavaScript 中的 this 关键字,才算迈入了 JavaScript 这门语言的门槛。
关于JavaScript中this的讨论已有很多,但理解起来仍有难度。
此处引用本站其他文章“yes this”中较为专业的解释。
接下来补充较为通俗的个人理解。
核心论点:this并非变量或属性,无法直接赋值,它始终指向调用当前代码的对象。
理解的关键在于牢记“this始终指向调用它的对象”,只要确定调用者,即可明确this的指向。
全局与函数调用中的this
场景1:
alert(this);
观察代码执行结果,弹窗显示“object window”或“object”,这表明this指向了一个对象,具体是哪个对象?
alert(this === window);
结果为'true',说明此时调用this的对象是window。
场景2:
var test = function(){
alert(this);
}
test();
推测上述代码的弹窗结果,是否与直接调用“alert(this)”一致?
var test = function(){
alert(this === window);
}
test();
执行代码后,是否弹出'true'?
如果情况如此简单,为何众多开发者仍对此感到困惑?
情况并未止步于此。
构造函数与new关键字的影响
场景3:
继续分析以下代码。
var test = function(){
alert(this === window);
}
new test();
为何这次结果变成了'false'?
回顾原则“this始终指向调用它的对象”:在第1处,直接调用该代码的对象是全局对象window;第2处虽为函数,但调用者仍是window(需注意函数本身是对象,但调用它的可能是其他对象);第3处使用了new关键字,此时情况发生变化。new作为构造函数创建了一个新的空对象,并由该新对象指向函数test中的代码,因此此时this不再指向window,而是指向构造函数创建的新对象。
场景4:
var test ={
'a':1,
'b':function(){
alert(this === test)
}
}
test.b();
基于上述论点,此时是否已清晰明了?
场景5:
var test ={
'a':1,
'b':function(){
alert(this === test)
}
}
var test1 = test;
test1.b();
结果并非“false”。虽然test1的值指向test,但test1仍引用test对象,两者指向同一对象。以下代码可作证明:
var test ={
'a':1,
'b':function(){
alert(this === test)
}
}
var test1 = test;
test.a = 2;
alert(test1.a);
若弹出“1”,请指正。
对象方法与嵌套函数中的this
场景6:更复杂的情况。
var test ={
'a':1,
'b':{
'b1':function(){
alert(this === test);
}
}
}
test.b.b1();
判断结果是“true”还是“false”?
根据前述理论,此时this不再直接由test调用,而是由test.b调用。以下代码可作证明:
var test ={
'a':1,
'b':{
'b1':function(){
alert(this === test.b);
}
}
}
test.b.b1();
场景7:进一步复杂化。
var test = function(){
var innerTest = function(){
alert(this === test);
}
innerTest();
}
test();
结果并非“true”。虽然innerTest看似由test调用,从而指向test,但错误在于谁实际调用了innerTest。此类函数实际上由window对象调用,无论嵌套多少层,最终调用者均为window。以下代码可作证明:
var test = function(){
var innerTest = function(){
alert(this === window);
var innerTest1 = function(){
alert(this === window);
}
innerTest1();
}
innerTest();
}
test();
apply/call绑定的this替换
场景8:特殊案例。
var test = function(){
alert(this === window);
}
var test1 = {
}
test.apply(test1);
此函数作用为“调用一个对象的方法,并以另一个对象替换当前对象”。因此,window对象被替换为test1,结果自然为'false'。以下代码可作证明:
var test = function(){
alert(this === test1);
}
var test1 = {
}
test.apply(test1);
类似地,call等方法的原理也与此相似。
原型继承与DOM事件中的this
场景9:原型继承,区别于字面量继承。
var test = function(){
}
var my = function(){
this.a = function(){
alert(this === mytest2);
}
}
var mytest = new my();
test.prototype = mytest;
var mytest2 = new test();
mytest2.a();
场景10:剩余部分可能涉及DOM对象。
<script>
var mytest = function(context){
alert(context.getAttribute('id'));
alert(this === window);
}
</script>
<div id="test" onclick="mytest(this)">aaaa</div>
通过上述示例,应已了解其中this分别代表的含义。