JavaScript中this的解释
在java中 this 指的是当前类的对象。而在js中其实this最根本的特性还是和OO(面向对象)语言中的定义相吻合的。This对象在执行时是基于函数的执行环境绑定的,当函数被作为某个对象的方法调用时,this就指向那个对象。当然js中的this还有一些特殊的特性和用法。
首先:所有 JavaScript 全局对象、函数以及变量均自动成为 window 对象的成员。全局变量是 window 对象的属性。全局函数是 window 对象的方法。
总结:
this指代为谁的对象,要看如何去调用这个函数。从根本上说它还是指的是当前对象(当前对象的执行环境或者说这个方法属于谁)。
当一个函数作为全局对象去调用的话,this均指向的是window对象[例如:window.test()一般window会省略,函数test中的this指的就是window对象]。
当一个函数作为对象的一个方法时,this指的就是当前对象。[例如:var obj={者里面的this指的就是当前对象obj}]。
当一个函数作为一个构造函数使用时,this这个时候指向的是函数构造出来的对象。[例如:var o = new obj();obj()函数中的this,值的是o这个对象]
另外在标签中事件触发时使用的this都指的是当前的标签(元素)对象,这里多数都会在带参函数中使用到。并且,定义在标签中的函数调用,会被解析成
标签对象.事件= function (event) {//...这里的this指的是event.currentTarget,也就是标签对象};
一、Js中this一般使用的情况
(了解了这几种下this指向谁,你就明白this)
1. 纯函数(作为函数调用)
2. 对象方法调用(作为方法调用)
3. 使用new调用构造函数
4. 内部函数
5. 使用call / apply
6.事件绑定
二、调试常用方法
alert();可以查看是否进函数,是否执行了某函数。还可以弹出某个对象的取值。
console.log(); console.info(String,Object);
console.asser(boolean);//断言false断言失败错误,true控制台不会输出什么
在控制台输出,可以开发者模式下,找到输出的内容。比alert表现更具体一点。
火狐有个非常强大的调试插件:Firebug(在附加组件中搜索firebug下载启用)
三、详细分析代码
1、纯函数中的this
var o = {prop:37};
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。因为这种调用方法,最原始的应该是:window.getName();但我们通常都会省略。调用它的对象是window。this指向当前调用它的对象,即window.
注:根据ECMAScript3和非严格的ECMAScript5对函数的调用的规定,this指代全局对象。然而在严格模式下则是undefined
2. 对象环境中
var o = {prop:37};
var name = 'this is window'; //定义window的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均指向了调用该方法的这个对象。创建对象的方式:<1>var a={}表示声名了一个,不包含任何自定义的属性和方法的对象。<2> var a=new a(); 其实和var a={}是等价的。在这个案例中getName()函数被作为testObj对象的一个方法,其均指向调用它的对象。
var o = {prop:37};
o.f = independent;
console.log(o.f) //37
o.b = {g:independent,prop:42};
console.log(o.b.g()); //42
function independent(){return this.prop;}
当我们使用o对象去调用f()方法时,this指向的是当前调用它的对象o,所以this.prop输出的是o对象中的prop属性。而当我们给o对象再添加一个对象时,此时o.b被作为一个对象,去调用g()方法时,this.prop输出的是o.b对象中的prop属性值。
3. 使用new调用构造函数
function getObj(){
console.log(this); //输出: getObj{}-this指向的新创建的getObj对象
}
new getObj(); //实例化了指向新生对象
运行结果分析:new 构造函数中的this指向新生成的对象。当我们使用new关键字实例化一个“类”对象的时候,Javascript引擎会在这个对象内部定义一个新的对象并将其存入this指针。所有此对象内部用到this的代码实际上都是指向这个新的对象。
例如更直观的:
function C(){ this.a = 37;}
var o = new C();
console.log(o.a); //输出结果:37
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);//这样可以获取到的this即指向testObj对象(对象拥有
name属性和getName()方法)
. }
handle();
}
}
testObj.getName();
运行结果分析:内部函数中的this仍然指向的是全局对象window。在内部函数中的this没有按预想绑定到外层函数中,而是绑定到了全局对象。这里涉及到了闭包的应用。闭包会将其空间扩展到外层函数空间之外,止步于全局空间,这时闭包中的this就指的是window对象。但是没有人希望内部函数被绑定到全局对象上。Js为了规避这种错误,设计了可以使用临时对象保存外层函数的this var self= this是testObj 对象的一个方式,所以此时的self指的是testObj对象,被保存在起来了,在内部函数中去使用时是可以取得的。
若是把上面案例: handle(); ——— 改为 new handle();
此时输出的结果:
console.log(this);//控制台输出:handle,因为使用了new实例化了handle构造函数
console.log(this.name);//控制台输出:undefined,因为handle对象中并没有name属性,所以会为undefined
console.log(self);//控制台输出:指向testObj对象
进一步验证了这个结论:this均指的是当前调用它的对象。
4.1换一种方式
var name="this is window";
var newname = "hhd";
function a(name){
this.name = newname;
function getname(){
alert(name)
console.log(this); //输出的window
console.log(this.name); // 输出的结果为this is window
}
console.log(this); //输出的结果object-->a
getname();
}
new a(name); //a对象中的this,均指向的是当前对象,实例化了构造函数
4.2补充说明
(先了解==和===区别
var a = 3;
var b = "3";
a==b 返回 true //等于
a===b 返回 false //严格等于会匹配类型和值)
var o={m:function(){
var self=this;
console.log(this===o); //true,对象方法调用,this指向调用该方法的对象
f();
function f(){ //定义一个嵌套函数
console.log(this===o); //false嵌套函数(内部函数)不会继承调用它的外函数的this
console.log(self===o); //true
}
}};
o.m();
5. 使用call / apply
Javascript引擎不允许我们自己写代码来做这样的事情,也就是说,在Javascript中,你不可以直接写this = someObj这样的代码。Javascript引擎通过以下两种方式允许我们显式指定this指针指代的对象:使用call / apply的函数里面的this指向绑定的对象。
这两个方法的用途都是在特定的作用域中调用函数。call()和apply()的第一个参数用作this的对象(即设置函数体内this对象的值)。Call(设置this的对象,其他参数...)而apply(设置this的对象,数组或者arguments对象)。
例如:
function sayColor(sPrefix,sSuffix) {
alert(sPrefix + this.color + sSuffix); //The color is blue a very nice color indeed.
};
//若是直接看sayColor这个函数的话,这里的this就得看这个函数的调用方式来决定this指代的是谁。
var obj = new Object();
obj.color = "blue";
sayColor.call(obj, "The color is ", " a very nice color indeed.");
//而我使用sayColor.call()去调用的话,指定了sayColor函数中的this指代的是obj这个对象,所以才会有“The color is blue a very nice color indeed.”
扩展:事件绑定
事件方法中的this应该是最容易让人产生疑惑的地方,大部分的出错都源于此。
//页面Element上进行绑定
<script type="text/javascript">
function btClick(){
console.log(this); //控制台输出: Window --- this指向的是全局对象
}
</script>
<body>
<button id="btn" onclick="btClick()" >点击</button>
</body>
上面这段代码相当于:
document.getElementById("btn").onclick = function(){
btClick();
}
btClick函数的所有权被没有发生转移。
//js中绑定方式(1)
<body>
<button id="btn">点击</button>
</body>
<script type="text/javascript">
function btClick(){
console.log(this); //控制台输出:<button id="btn">点击</button> //this指向的是HTMLButtonElement按钮对象
}
document.getElementById("btn").onclick = btClick;
document.getElementById("btn").onclick(); //默认点击
</script>
//创建了一个文档对象(HTMLButtonElement按钮对象)去调用了btClick()这个方法,此时的btClick方法被绑定为该元素对象的一个方法。所以这里面的this指的是该元素对象。
//js中绑定方式(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><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>
运行结果分析:以上2种常用事件绑定方法,在页面Element上的进行事件绑定(οnclick="btClick();"),this指向的是全局对象;而在js中进行绑定,除了attachEvent绑定的事件方法(this指向的是全局对象)外,this指向的是绑定事件的Elment元素。
7、参数上的应用
另外在参数上的用法,指的是当前的标签对象 this.id 这里指的是button的id属性
<button id="a1" onclick="btClick(this.id)">点击</button> //弹出a1
<button id="a2" onclick="btClick(this.id)">点击</button> //弹出a2
<script type="text/javascript">
function btClick(num){
alert(num) ; //a1 / a2
alert(this) ; //window
}
</script>
以上代码运行时会被解析为:
<script type="text/javascript">
document.getElementById("a1").onclick = function (event) {
alert(event); //object MouseEvent
alert(event.currentTarget); //object HTMLButtonElement
alert(target); //object HTMLButtonElement
alert(this); //object HTMLButtonElement
};
</script>
例如:
<input id="myBtn" name="btnTest" type="button" value="点击我" >
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function (event) {
console.log(event.currentTarget); //[object HTMLInputElement]
console.log(event.target); //[object HTMLInputElement]
alert(event.currentTarget === this); //ture
alert(event.target === this); //ture
};
</script>
<input id="myBtn" name="btnTest" type="button" value="点击我" >
<script type="text/javascript">
document.body.onclick = function (event) {
alert(event.currentTarget === document.body); //ture
alert(this === document.body); //ture
alert(event.target === document.getElementById("myBtn")); //ture
};
</script>
event.currentTarget //事件处理程序真正注册的元素(即冒泡或者捕获是真正走到元素目标)
event.target //是真正的鼠标点击的目标元素(到达真正目标)
练习:
var t =function(){
this.a = "我是t";
alert(this);
setInterval(function(){
alert(this.a);
},1000);
}
new t();
第一个弹出:object Object //var t =function()这种写法实际会解析成:var t =new Function();
var function_name = new function(arg1, arg2, ..., argN, function_body)
第二个弹出:undefined //定时器他的所属环境是全局所以,定时器中的this代表的是window对象