this关键字是javascript理解中的老大难,尤其作为一个新手,常常会被它弄糊涂,搞不清楚this到底指向“谁”。本文将分析this的各种应用场景。
1.在HTML元素事件属性中i使用this关键字
这种用法是最为常见的方式(javascirpt: EventHandler(this)),在这种情况下,this在哪个元素中,它表示的是就是那个对象。举例说明:
<html>
<head>
<title>函数</title>
</head>
<body>
<img src="xsd.jpg" οnclick="JavaScript:alert(this.src);">
<form name="ttt">
<input type="text" name="ddd" value="ddaaa" οnclick="checkit(this)">
</form>
</body>
<Script language="JavaScript">
function checkit(obj){
if (obj.value == "") {
alert("空值");
}
else {
alert(obj.value);
}
}
</Script>
</html>
2.DOM方式在事件处理函数中使用this关键字
<div id="elmtDiv">division element</div>
<script language="javascript">
var div = document.getElementById('elmtDiv');
div.attachEvent('onclick', EventHandler);
function EventHandler() {
// 在此使用this
}
</script>
这时的EventHandler()方法中的this关键字,
指示的对象是IE的window对象。这是因为EventHandler只是一个普通的函数,对于attachEvent后,脚本引擎对它的调用和div对象本身没有任何的关系。同时你可以再看看EventHandler的caller属性,它是等于null的。如果我们要在这个方法中获得div对象引用,应该使用:
this.event.srcElement.value。
3.用DHTML方式在事件处理函数中使用this关键字
<script language="javascript">
var div = document.getElementById('elmtDiv');
div.onclick = function() {
// 在此使用this
};
</script>
这里的this关键字指示的内容是div元素对象实例,在脚本中使用DHTML方式直接为div.onclick赋值一个EventHandler的方法,等于为div对象实例添加一个成员方法。这种方式和第一种方法的区别是,第一种方法是使用HTML方式,而这里是DHTML方式,后者脚本解析引擎不会再生成匿名方法。
4、类定义中使用this关键字
在 ECMAScript 中,要掌握的最重要的概念之一是关键字 this 的用法,它用在对象的方法中。关键字 this 总是指向调用该方法的对象。
<pre name="code" class="javascript"><span style="font-family: Arial, Helvetica, sans-serif;"> <script type="text/javascript"></span>
function Car(sColor, iDoors, iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.showColor = function() {
alert(this.color);
};
}
var oCar1 = new Car("red", 4, 23);
var oCar2 = new Car("blue", 3, 25);
oCar1.showColor();//red
oCar2.showColor();//blue alert(oCar1.showColor==oCar2.showColor)//false
</script>
在上面的代码中,关键字 this 用在对象的 showColor() 方法中。在此环境中,this 等于 oCar。如果不用对象或 this 关键字引用变量,ECMAScript 就会把color看作局部变量或全局变量。然后该函数将查找名为 color 的局部或全局变量,但是不会找到。结果如何呢?该函数将在警告中显示 "null"。
缺陷:每个实例对象的showColor方法一模一样,每一次生成一个实例,都必须为重复的内容,多占用一些内存。这样既不环保,也缺乏效率。
能不能让drivers属性和showColort()方法在内存中只生成一次,然后所有实例都指向那个内存地址呢?回答是可以的。
function Car() {
}
Car.prototype.color = "blue";
Car.prototype.doors = 4;
Car.prototype.mpg = 25;
Car.prototype.drivers = new Array("Mike","John");
Car.prototype.showColor = function() {
alert(this.color);
};
var oCar1 = new Car();
var oCar2 = new Car();
oCar1.drivers.push("Bill");
alert(oCar1.drivers); //输出 "Mike,John,Bill"
alert(oCar2.drivers); //输出 "Mike,John,Bill"
alert(oCar1.showColor==oCar2.showColor)//true
代码2 原型 Prototype模式
该方式利用了对象的 prototype 属性,可以把它看成创建新对象所依赖的原型。
原型方式的缺陷:这种方式下,对象间(oCar1、oCar2)共享属性指向的是对象(new Array function)。
这个构造函数没有参数。使用原型方式,不能通过给构造函数传递参数来初始化属性的值,因为 Car1 和 Car2 的 color 属性都等于 "blue",doors 属性都等于 4,mpg 属性都等于 25。这意味着必须在对象创建后才能改变属性的默认值,这点很令人讨厌,但还没完。真正的问题出现在属性指向的是对象,而不是函数时。
函数共享不会造成问题,但对象却很少被多个实例共享。
解决方法:
<script type="text/javascript">
function Car(sColor, iDoors, iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike", "John");
}
Car.prototype.showColor = function() {
alert(this.color);
};
var oCar1 = new Car("red", 4, 23);
var oCar2 = new Car("blue", 3, 25);
oCar1.drivers.push("Bill");
alert(oCar1.drivers); //输出 "Mike,John,Bill"
alert(oCar2.drivers); //输出 "Mike,John"
</script>
5.2&4综合题
<script language="javascript">
function JSClass() {
this.m_Text = 'division element';
this.m_Element = document.createElement('DIV');
this.m_Element.innerHTML = this.m_Text;
//this.m_Element.attachEvent('onclick', this.toString);
}
JSClass.prototype.Render = function() {
document.body.appendChild(this.m_Element);
}
JSClass.prototype.toString = function() {
alert(this.m_Text);
};
var jc = new JSClass();
jc.Render();
jc.ToString();
</script>
页面运行后会显示:"division element",确定后点击文字"division element",将会显示:"undefined"。
6.function中this的使用
<script language="javascript">
function OuterFoo() {
this.Name = 'Outer Name';
function InnerFoo() {
var Name = 'Inner Name';
alert(Name + ', ' + this.Name);
}
return InnerFoo;
}
OuterFoo()();
</script>
根据第二点的理解,OuterFoo和InnerFoo都是一个普通的函数,所以函数中的this都是指向Window对象。那么输出应该为"
Inner Name, undefined",但是结果却不是这样。输出见下图: