<%@ page contentType="text/html; charset=gb2312"%> "this" of JavaScript
网站公告:   ◆北天JAVA技术网热情为java爱好者服务,本网内容包括JAVA(JSP、servlet、EJB、webservice、j2ee、javabean、应用服务器、JavaScript),数据库(MYSQL、SQL Server、Sybase、Oracle、DB2、数据库综合知识),设计研究(设计模式、Struts、Spring、Hibernate、设计框架、设计综合知识),WEB2.0新技术(主要介绍AJAX),以及各种技术的入门、实例、例子等等,欢迎各位多来坐坐!◆  诚邀各位JAVA爱好者加盟!◆  本网站内容丰富,更新快,保证每周20篇以上!  
加入收藏
设为首页
联系站长
承接项目
  相关资源:网站首页 | 免费培训学院 | 技术论坛 | JAVA聊天室 | 作家专栏 | 开发工具 | 认证考试 | 会员俱乐部
  JAVA技术初学者园地 | jsp与servlet | javascript | Java源代码 | EJB | web service | 应用服务器 | JAVA综合知识
  设计研究设计模式 | 设计框架 | Struts | Spring | Hibernate | 开源项目 | 面向对象设计 | 设计综合知识
  数 据 库MYSQL | SQL Server | Sybase | Oracle | DB2 | Informix | Access | 数据库综合知识
  其他资源:AJAX新技术 | 网站开发 | ERP软件 | OA办公软件 | 商业智能BI | 开发综合知识 | 承接项目 | 项目试用

 
 
"this" of JavaScript
     发布者: 发布时间:2006-11-10

this是JavaScript中功能最强大的关键字之一。不幸的是,如果你不知道它具体怎么工作,你将很难正确使用它。

下面我来阐述如何在事件处理中来使用this,之后我会附加一些this相关的例子。

Owner

接下来文章中我们将要讨论的问题是:在函数doSomething()中this所指的是什么?

代码
  1. function doSomething() {   
  2.   this.style.color = '#cc0000';   
  3. }  

在JavaScript中,this通常指向的是我们正在执行的函数本身(译者注:用owner代表this所指向的内容),或者是,指向该函数所属的对象。当我们在页面中定义了函数doSomething()的时候,它的owner是页面,或者是JavaScript中的window对象(或 global对象)。对于一个onclick属性,它为它所属的HTML元素所拥有,this应该指向该HTML元素。

这种“所有权”就是JavaScript中面向对象的一种方式。在Objects as associative arrays中可以查看一些更多的信息。

如果我们在没有任何更多准备情况下执行doSomething(),this关键字会指向window,并且该函数试图改变window的 style.color。因为window并没有style对象,这个函数将非常不幸的运行失败,并产生JavaScript错误。

Copying

因此如果我们想充分利用this,我们不得不注意使用this的函数应该被正确的HTML元素所拥有。换句话说,我们应该复制这个函数到我们的onclick属性。Traditional event registration会关心它。

代码
  1. element.onclick = doSomething;  

这个函数被完整复制到onclick属性(现在成为了函数)。因此如果这个event handler被执行,this将指向HTML元素,并且该元素的颜色得以改变。

这种方法使得我们能够复制这个函数到多个event handler。每次this都将指向正确的HTML元素:

这样你就可以最大限度使用this。每当执行该函数,this所指向的HTML元素都正确响应事件,这些HTML元素拥有doSomething()的一个拷贝。

Referring

然而,如果你使用inline event registration(内联事件注册)

代码
  1. <element onclick="doSomething()">  

你将不能拷贝该函数!反而这种差异是非常关键的。onclick属性并不包含实际的函数,仅仅是一个函数调用。

代码
  1. doSomething();  

因此,它将声明“转到doSomething()并且执行它”。当我们到达doSomething(),this关键字又重新指向了全局的window对象,函数返回错误信息。

The difference

如果你想使用this来指向HTML元素响应的事件,你必须确保this关键字被写在onclick属性里。只有在这种情况下它才指向event handler所注册的HTML元素。

代码
  1. element.onclick = doSomething;   
  2. alert(element.onclick)  

你将得到

代码
  1. function doSomething() {   
  2.   this.style.color = '#cc0000';   
  3. }  

正如你所见,this关键字被展现在onclick函数中,因此它指向HTML元素。

但是如果执行

代码
  1. <element onclick="doSomething()">   
  2. alert(element.onclick)  

你将得到

代码
  1. function onclick() {   
  2.   doSomething()   
  3. }  

这仅仅是到doSomething()函数的一个引用。this关键字并没有出现在onclick函数中,因此它不指向HTML元素。

例子--拷贝

下面的例子中,this被写入onclick函数里:

代码
  1. element.onclick = doSomething   
  2. element.addEventListener('click', doSomething, false)   
  3. element.onclick = function() {this.style.color = '#cc0000';}   
  4. <element onclick="this.sytle.color = '#cc0000';">  

例子--引用

下述情况中,this指向window:

代码
  1. element.onclick = function() {doSomething()}   
  2. element.attachEvent('onclick', doSomething)   
  3. <element onclick="doSomething()">  

注意attachEvent()的出现。Microsoft event registration model最主要的弊端是attachEvent()创建了一个指向函数的引用,而不是复制它。因此有时不可能知道哪个HTML正在处理该事件。

组合使用

当使用内联事件注册时,你可以将this发送到函数以至于可以正常使用:

代码
  1. <element onclick="doSomething(this)">   
  2. function doSomething(obj) {   
  3.   //this出现在event handler中并被发送到函数   
  4.   //obj指向HTML元素,因此可以这样:   
  5.   obj.style.color = '#cc0000';   
  6. }  

原文题目:The this keyword
原文链接:http://www.quirksmode.org/js/this.html
译文链接:http://www.blogjava.net/flyingis/archive/2006/09/15/69888.html

评论    共 8 条 发表评论
flyingis     2006-09-15 18:29

翻译不准确的地方请大家指正

jianfeng008cn     2006-09-19 13:08

主题:"this" of JavaScript [翻译]
链接:http://www.javaeye.com/topic/24457

我不赞成该文的观点,所以针对该文提出我自己的理解,如有不当之处,还请各位多多指教!

我觉得该文章对Copy和Referring的概念的理解会使大家陷入困境。

下面我针对该文的一些行文附上自己的理解,方便大家对比。

引用
代码:
function doSomething() {
this.style.color = '#cc0000';
}

Copying
代码
element.onclick = doSomething;

ps:

我觉得理解javascript这种解释型语言,应该从语言“运行时”这个角度来思考问题,注意“时间轴”上所发生的事情。
引用应该理解成js运行时指向一段内存空间的引用对象吧。
上面应该也只是引用而已,因为javascript的对象的属性都是引用,运行时,上面的例子只是将element的onclick属性指向了内存中分配的doSomething函数对象而已。
当然如果如果有两个引用对象开始都指向了同一个匿名对象,如果其中一个改变,并不会该变另外一个,因为其中一个的改变,其实是分配了新的对象给他,并不是改变原来他所指向的对象。
也许你会问: 如果element2.onclick = doSomething; 解释是:element2的onclick属性也指向了内存中分配的新的doSomething函数对象。
那下面的referring该如何解释呢?这里讲到了inline event registration(内联事件注册) 这是javascript和dom、bom对象相互协调工作的一种机制,我们可以这样理解,dom、bom对象的事件属性,在js里面的处理是这样的:
js针对这些属性会让他们指向内存中的匿名函数对象A,在匿名函数对象里面再调用我们指定的函数B。运行时,如果B函数的参数中含有this自然是把A函数中的this对象传递了过去。

我感觉:
作者该文章,从自己的使用经验上很好的总结了this在javascript的事件机制中的灵活作用,但是作者的这样的分析却违背了javascript语言的本质。
正所谓,万变不离其宗!
我们应该牢牢把握javascript语言的本质:基于对象的、弱类型语言、解释型语言。

那么是不是javascript中对象就不存在属性复制呢?答案是 不存在!

这里我要纠正大家一直都在说的一个看法,就是prototype中对象的继承是通过“拷贝”来实现的,这种理解是错误的,这样的理解将导致copy和referring两种分类的误区,代码如下:

Object.extend = function(destination, source) {
for (property in source) {
destination[property] = source[property];
}
return destination;
}

在这里我们可以看到destination对象和source对象的同名属性只是指向了内存相同的对象而已,根本没有拷贝的情况发生,反个角度思考,如果是拷贝,那么我们需要在内存中分别为他们生成新的空间了,实际情况并非如此。这也是js节约内存的一种做法,也许你会问当source对象的属性改变以后,destination的属性根本没有变化呀,是的,那是因为source对象的属性改变只是他指向了内存中重新生成的一个对象,原来的所指向的内存中的那个对象并没有改变。

下面我附上一个例子:

代码
  1. function MakeArray(n) {   
  2.     this[0] = "anuary"  
  3.     this[1] = "February"  
  4.     this[2] = "March"  
  5.     this[3] = "April"  
  6.     this[4] = "May"  
  7.     this[5] = "June"  
  8.     this[6] = "July"  
  9.     this[7] = "August"  
  10.     this[8] = "September"  
  11.     this[9] = "October"  
  12.     this[10] = "November"  
  13.     this[11] = "December"  
  14.     this['length'] = n   
  15.     return this  
  16. }   
  17.   
  18. theMonths = new Object();   
  19. theMonths.fun=MakeArray;   
  20. //这里打印出来看看也是有目的的哦   
  21. for(var p in theMonths){   
  22.     alert("property:" + p + "==>value:" + theMonths[p]);   
  23. }   
  24. theMonths.fun(12);   
  25.   
  26. var p2 = new Object();   
  27. for(var p in theMonths ){   
  28.   p2[p]=theMonths[p];   
  29. }   
  30. //先打印一遍   
  31. for(var p in theMonths){   
  32.     alert("property:" + p + "==>value:" + theMonths[p]);   
  33. }   
  34. for(var p in p2){   
  35.     alert("property:" + p + "==>value:" + p2[p]);   
  36. }   
  37.   
  38. theMonths.length=100;   
  39.   
  40. //再印一遍 要理解为什么我会这样打印2遍哦   
  41. for(var p in theMonths){   
  42.     alert("property:" + p + "==>value:" + theMonths[p]);   
  43. }   
  44. for(var p in p2){   
  45.     alert("property:" + p + "==>value:" + p2[p]);   
  46. }  

引用

Referring
然而,如果你使用inline event registration(内联事件注册)
代码
<element onclick="doSomething()">
因此,它将声明“转到doSomething()并且执行它”。
当我们到达doSomething(),this关键字又重新指向了全局的window对象,函数返回错误信息。
The difference
如果你想使用this来指向HTML元素响应的事件,你必须确保this关键字被写在onclick属性里。只有在这种情况下它才指向event handler所注册的HTML元素。

代码
element.onclick = doSomething;
alert(element.onclick)
打印可以看到:
function doSomething() {
this.style.color = '#cc0000';
}

this关键字被展现在onclick函数中,因此它指向HTML元素。
但是如果执行
代码
<element onclick="doSomething()">
alert(element.onclick)
将打印看到:
function onclick() {
doSomething()
}

ps:
上面这段代码只是解释了inline event registration(内联事件注册)
在javascript里是怎么实现的,与this的本质并没有任何关联。内联事件注册 上面我说了,js只是在内存中让元素的属性指向了新分配的匿名函数对象A,如果我们自己没有在标签中写函数的话,那么默认是空函数 什么也不做,如果我们写了函数B,那么在匿名空函数A中调用我们的函数B,如果B里面有this,this当然不会想当然地指向元素而是指向window了,否则自然是将A函数中的this传递进B函数。

引用

例子--拷贝
下面的例子中,this被写入onclick函数里:
代码
element.onclick = doSomething
element.addEventListener('click', doSomething, false)
element.onclick = function() {this.style.color = '#cc0000';}
<element onclick="this.sytle.color = '#cc0000';">
例子--引用
下述情况中,this指向window:
代码
element.onclick = function() {doSomething()}
element.attachEvent('onclick', doSomething)
<element onclick="doSomething()">
注意attachEvent()的出现。
Microsoft event registration model最主要的弊端是attachEvent()创建了一个指向函数的引用,而不是复制它。
因此有时不可能知道哪个HTML正在处理该事件。
组合使用
当使用内联事件注册时,你可以将this发送到函数以至于可以正常使用:
代码
<element onclick="doSomething(this)">
function doSomething(obj) {
//this出现在event handler中并被发送到函数
//obj指向HTML元素,因此可以这样:
obj.style.color = '#cc0000';
}

ps:
引用
Microsoft event registration model最主要的弊端是attachEvent()创建了一个指向函数的引用,而不是复制它。

该语句可能会让我们误以为inline event registration(内联事件注册)这样的处理方式有弊端,其实不然,这样做给了我们充分的自由,在触发了元素的事件以后,我们可以选择该处理什么范围内的事情,是全局还是针对该元素 控制权在我们自己手中。

flyingis     2006-09-28 16:03

@jianfeng008cn
感谢精彩回复。

总结一下你的回答,归纳为以下几点:

1.当两个对象引用A、B指向同一个对象C,引用A发生改变时,会在内存中产生一个新的对象,B所指的内容不发生变化;
2.JavaScript对内存使用是通过引用来进行的,不存在拷贝。

其实我觉得作者将Copying引用进来,本意应该是想将问题描述的更通俗一些,不料产生了歧异。"Copying"(加上了引号)之所以产生,正如你所说,是在对象内容发生改变的时候,在内存中会生成一个新的对象,原来对象还在内存中,这个过程就是"Copying",当然站在面向对象的角度上来说,当A指向对象C的时候,中间只有引用,而没有Copying。

代码
  1. <element onclick="doSomething()">  // X方案   
  2. element.onclick = doSomething();   // Y方案  

上面两种方案的差别在于,X方案是在onclick的匿名函数中去调用doSomething(),Y方案中是将onclick指向了doSomething(),因此在doSomething()中使用this,其含义就产生了差别。在X方案中,如果显式的将this作为doSomething的参数传入,this自然就指向了onclick所属的HTML元素,得到我们所需要的结果。

Lucas Lee     2006-09-29 12:24

脚本语言看似简单,用起来实际还挺复杂。
只是把复杂性推迟了而没有隐藏。

Readonly     2006-09-29 14:53

这个文章把简单的东东讲复杂了,在function内部的this,是指向调用这个function时的当前对象
写这样一个简单的script看看就明白了:
<script>
function test() {
alert(this);
}

test.call();
test.call("String Object");
</script>

文章里面说的各种情况无非是Function.call(thisArg[, arg1[, arg2[, ...]]]),所传递的thisArg不一样而已。

参考文档:
http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Function:call

http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Operators:Special_Operators:this_Operator

jianfeng008cn     2006-09-30 09:25

代码
  1. [code]<element onclick="doSomething()">  // X方案   
  2. element.onclick = doSomething();   // Y方案   

你的Y方案和你说的意思不一样哦,你这样写是把doSomething函数的执行结果赋给了element.onclick
我想正确格式应该为:

代码
  1. element.onclick = doSomething;   // Y方案  

jianfeng008cn     2006-09-30 09:31

Readonly 写道
这个文章把简单的东东讲复杂了,在function内部的this,是指向调用这个function时的当前对象
写这样一个简单的script看看就明白了:
<script>
function test() {
alert(this);
}

test.call();
test.call("String Object");
</script>

文章里面说的各种情况无非是Function.call(thisArg[, arg1[, arg2[, ...]]]),所传递的thisArg不一样而已。

参考文档:
http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Function:call

http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Operators:Special_Operators:this_Operator


代码
  1. function showName(name){   
  2.   alert("name:"+name);   
  3. }   
  4. var obj = new Object();   
  5. obj.fun=showName;   
  6. obj.fun("jianfeng008cn");   
  7. delete obj.fun;   

代码
  1. function test() {   
  2.     alert(this);   
  3. }   
  4. test.call();   
  5. test.call("String Object");   

这两段代码的执行机制是一样的 ,属于语言支持的部分,这和上面讲的 事件机制 虽有几分类似 但在js的执行过程中还是有很大的不同的 ,我觉得这样去理解是可以,但不是正道。

flyingis     2006-10-01 22:31

jianfeng008cn 写道
代码
  1. [code]<element onclick="doSomething()">  // X方案   
  2. element.onclick = doSomething();   // Y方案   

你的Y方案和你说的意思不一样哦,你这样写是把doSomething函数的执行结果赋给了element.onclick
我想正确格式应该为:

代码
  1. element.onclick = doSomething;   // Y方案  

纠正的极是

(转载文章请保留出处:北天JAVA技术网(www.java114.com))
 
更多精彩文章:
征服ajax - web20开发技术详解试读版
一个经典的javascript教程
新编辑的五日学会js教程
网络编程基础篇之 java script
突破javascript编程实例五十讲
深入学习:java servlet开发与实例
 
最近评论:
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(2029)
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(2004)
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(8955)
        
冰封的往事!
wow power leveling,wow gold,wow power leveling,wow gold max(8776)
        
冰封的往事!
wow power leveling,wow gold,WoW Gold,wow gold max(6380)
        
标 题:   
内 容:   
 
                                  
 
免责声明:该文章由网友发表,如果对您造成侵权,请联系站长

首页 - 承接项目 - 网站地图 - 联系我们 -
版权所有北天JAVA技术工作室 ICP证号:粤ICP备06079815号