说到js我们就不得不多this,这东西很多时候让人不知道它代表了谁?我们根据js的书写场景简单看看this在不同地方都代表谁。
1.在全局下,this的指向
我们运行下面页面:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> </body> <script> alert(this); </script> </html>
弹出:
说明this代表了window对象,也就是指向window。
我们知道全局设置的变量等都是挂载window下的,可以通过window.xx获取到,同样window也可以缺省(就是不写):
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> </body> <script> var a=123; var b=456; alert(a) alert(window.a); alert(this.a); </script> </html>
三种写法都可输出变量a的值,window使我们js的全局对象,除了我们自定义全局变量挂载他的下面,很多原生提供的东西都是挂在window下的:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> </body> <script> alert(document.documentElement.tagName); alert(window.document.documentElement.tagName); alert(setInterval); alert(window.setInterval); alert(parseInt); alert(window.parseInt); </script> </html>
是不是通过window.也可以调用。
总结就是全局下的this就是指代window,window是js的根,很多东西都挂在在window下,可以通过window去访问,同样缺省可用。
2.dom+事件的this
我们操作页面,交互的核心之一就是事件,事件触发,我们为了让js可以正常的运行,一般会这样书写:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> </body> <script> window.onload=function(){ alert(this); }; </script> </html>
load事件中书写代码,这样就可以保证页面加载完去执行,这时候this发现指向了window,我们好像看不出来什么,我们在页面写几个标签,然后加入click事件,去弹出this:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> <p style="height:100px;" id="dom">dom</p> </body> <script> window.onload=function(){ var abc=document.getElementById("abc"); var dom=document.getElementById("dom"); abc.onclick=function(){ alert(this); }; dom.onclick=function(){ alert(this); }; }; </script> </html>
div和p点击弹出情况:
点击div是指向div元素,点击p指向p元素(p的全名),我们可能还疑惑,我们更具体输出内容:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> <p style="height:100px;" id="dom">dom</p> </body> <script> window.onload=function(){ var abc=document.getElementById("abc"); var dom=document.getElementById("dom"); abc.onclick=function(){ alert(this.innerHTML); }; dom.onclick=function(){ alert(this.innerHTML); }; }; </script> </html>
弹出:
这次是不是完全清楚了,点击那个this就指向了那个元素,我们利用dom具有的属性就可以具体输出对应内容。
此时我们知道了this指向的就是添加事件的对象元素(也就是标签),上面window加入load事件,this指向的是window也就是添加load事件对象。
总结,在添加事件后,this指向添加事件的对象,并且指向的是最近的对象,div就指向div而不是window。
3.this在事件中指向冲突问题
我们在上面例子,知道this指向有就近的原则一样,根据所在位置,所在环境会指向最近的那个对象,比如div中的this就是指向div,我们往上反一级的this就指向了window,知道this所指向受到上下文影响。
我们执行下面的例子:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> <p style="height:100px;" id="dom">dom</p> </body> <script> window.onload=function(){ var abc=document.getElementById("abc"); var dom=document.getElementById("dom"); abc.onclick=function(){ setInterval(function(){ this.innerHTML=this.innerHTML+1; },500); }; dom.onclick=function(){ alert(this.innerHTML); }; }; </script> </html>
我想做的就是点击后,内部的内容不断+1,可是我们发现并没有+1,
我把setinterval补全:
我们使用的这个方法是通过window调用,根据this指向上下文对象,猜测this指向了window,所以不出现想要结果,我们测试this:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> <p style="height:100px;" id="dom">dom</p> </body> <script> window.onload=function(){ var abc=document.getElementById("abc"); var dom=document.getElementById("dom"); abc.onclick=function(){ window.setInterval(function(){ alert(this) //this.innerHTML=this.innerHTML+1; },500); }; dom.onclick=function(){ alert(this.innerHTML); }; }; </script> </html>
点击后,不断弹出:
说明间隔函数的this替掉事件this了,没有指向div,简单就是名字一样了,最简单解决思路就是外部或者内部把this赋值到其他名字变量里,这样就不会冲突了:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> <p style="height:100px;" id="dom">dom</p> </body> <script> window.onload=function(){ var abc=document.getElementById("abc"); var dom=document.getElementById("dom"); abc.onclick=function(){ var that=this; window.setInterval(function(){ that.innerHTML=that.innerHTML+1; },500); }; dom.onclick=function(){ alert(this.innerHTML); }; }; </script> </html>
是不是开始不断+1,把事件this赋值给that,我们的间隔函数去获取that执行处理。有人可定想间隔里面this给that,但是this还是this也就是window,这明显是不可行的。
总结冲突问题,把外部this指向内容赋值给自定义变量。
4.类和this
我们上面都是说事件中的this,下面介绍在语法中this的指向问题。
标题是类和this,类就是创建对象用的,我们从对象入手,然后介绍类中的this。
1.对象类型和this
我们创建对象和输出this:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> <p style="height:100px;" id="dom">dom</p> </body> <script> window.onload=function(){ var obj={}; obj.a=123; obj.b=function(){alert(this)}; obj.b(); }; </script> </html>
弹出obj,猜测是指向定义的obj了,进一步测试:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> <p style="height:100px;" id="dom">dom</p> </body> <script> window.onload=function(){ var obj={}; obj.a=123; obj.b=function(){alert(this.a)}; obj.b(); }; </script> </html>
弹出:
也就是输入obj的a属相值,说明obj类型内this指向的就是本身。
2.类和this
类可以创建对象,这个我们肯定非常熟悉,指代this指向的就是每次创建的对象,
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> <p style="height:100px;" id="dom">dom</p> </body> <script> window.onload=function(){ function Aa(arg){ this.a=arg; }; alert(new Aa(1).a); alert(new Aa(2).a); }; </script> </html>
类里面的this就是每次创建的对象,类是抽象和相似定义,避免了下面这种创建对象的重复性:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> <p style="height:100px;" id="dom">dom</p> </body> <script> window.onload=function(){ function Aa(arg){ this.a=arg; }; alert(new Aa(1).a); alert(new Aa(2).a); var obj1={a:1}; var obj2={a:2}; alert(obj1.a); alert(obj2.a); }; </script> </html>
类里面的this同样具有冲突问题,比如类里面调用setinterval方法去改变某个属性,那么是不是间隔this指向的是window,我们this.a就不能去改变了,解决冲突我们还是可以利用that这种方式:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> <p style="height:100px;" id="dom">dom</p> </body> <script> window.onload=function(){ function Aa(id){ this.a=document.getElementById(id); var that=this; this.init=function(){ this.add(); } this.add=function(){ setInterval(function(){ that.a.innerHTML=that.a.innerHTML+1; },500) }; }; new Aa("abc").init(); new Aa("dom").init(); }; </script> </html>
是不是就成功实现了两个元素内容增加,每次new都是开辟空间让对象对执行对象处理。
我们可能还如加入事件处理,更加的复杂封装:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> <p style="height:100px;" id="dom">dom</p> </body> <script> window.onload=function(){ function Aa(id){ this.a=document.getElementById(id); var that=this; this.init=function(){ this.a.onclick=function(){ this.add(); }; } this.add=function(){ setInterval(function(){ that.a.innerHTML=that.a.innerHTML+1; },500) }; }; new Aa("abc").init(); new Aa("dom").init(); }; </script> </html>
执行失败,我们仔细分析,发现事件this只的是this.a,就是指向的元素;我们调用add方法挂在指向new的对象this,而不是指向元素this。
既然冲突了,还是利用that处理:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> <p style="height:100px;" id="dom">dom</p> </body> <script> window.onload=function(){ function Aa(id){ this.a=document.getElementById(id); var that=this; this.init=function(){ this.a.onclick=function(){ that.add(); }; } this.add=function(){ setInterval(function(){ that.a.innerHTML=that.a.innerHTML+1; },500) }; }; new Aa("abc").init(); new Aa("dom").init(); }; </script> </html>
that肯定指向new的对象,局部this不会替换他,我们就可以调用到了。
5.事件this的相等判断
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> <p style="height:100px;" id="dom">dom</p> </body> <script> window.onload=function(){ var abc=document.getElementById("abc"); abc.onclick=function(){ if(this==abc){ alert(1); }else{ alert(2); }; }; }; </script> </html>
核心测试:
相等判断没有问题,我们知道this和abc代表的是元素对象,我们就会想到obj类型有没有相等判断能力:
var obj1={a:1}; var obj2={a:1}; if(obj1==obj2){ alert(1); }else{ alert(2); };
1和2证明不是相同的东西:
var obj1=123; var obj2=123; if(obj1==obj2){ alert(1); }else{ alert(2); };
1和2相同,在一些特殊类型是不具有判断能力的。
上面是自己琢磨的问题,还是回到事件和this,我们知道找div除了用id还有其他方法,我们测试:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>this</title> <style> *{ margin:0; padding:0;} html{height:100%;} body{height:100%;} </style> </head> <body> <div style="height:100px;" id="abc">789</div> <p style="height:100px;" id="dom">dom</p> </body> <script> window.onload=function(){ var abc=document.getElementById("abc"); var abc2=document.getElementsByTagName("div")[0]; abc.onclick=function(){ if(this==abc2){ alert(1); }else{ alert(2); }; }; abc2.onmousemove=function(){ if(abc2==abc){ alert(3); }else{ alert(4); }; }; }; </script> </html>
给abc和abc2都可以监听事件,说明可以多对一的操作元素对象。同样不同方式找到的元素如果代表同一个元素有判断相等能力。