`
flyingis
  • 浏览: 294551 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论
阅读更多
    this是JavaScript中功能最强大的关键字之一。不幸的是,如果你不知道它具体怎么工作,你将很难正确使用它。

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

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

function doSomething() {
  this.style.color = '#cc0000';
}


    在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会关心它。

element.onclick = doSomething;


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



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



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

    Referring

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

<element onclick="doSomething()">


    你将不能拷贝该函数!反而这种差异是非常关键的。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()
}


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

    例子--拷贝

    下面的例子中,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';
}


    原文题目:The this keyword
    原文链接:http://www.quirksmode.org/js/this.html
    译文链接:http://www.blogjava.net/flyingis/archive/2006/09/15/69888.html
分享到:
评论
16 楼 sp42 2007-05-09  
说句真心话,其实js就这么几回事,只不过对JS混淆视听的东西太多,而且最重要的是没有所谓的offical guide那里要命!
15 楼 zhangzhaofeng 2007-05-09  
sp42 写道
引用
在function(){}中引入this是一个动态的变量。谁去调就指向谁。

说到点子上了
其实function(){
...
this ..
}
是一个过程的“模板”
谁都可以用这个“模板”
this就是代表这个“谁”



觉的这个写的很明了
14 楼 zhangzhaofeng 2007-05-09  
sp42 写道
引用
在function(){}中引入this是一个动态的变量。谁去调就指向谁。

说到点子上了
其实function(){
...
this ..
}
是一个过程的“模板”
谁都可以用这个“模板”
this就是代表这个“谁”

觉的这个说的简单明了
13 楼 sp42 2007-05-08  
function foo(){
		alert(typeof this)
		alert(typeof this.constructor)
	};
	foo.call(8);
	foo.call([]);
	foo.call("j"); //为何我发现这里不是string的,当alert(typeof this.constructor)
的时候?
	foo.call({});
	foo.call(null);
	foo.call(undefined);
	foo.call(NaN);
 	foo.call(/re/ig);
 	foo.call(new String("dd"))
12 楼 sp42 2007-05-08  
引用
在function(){}中引入this是一个动态的变量。谁去调就指向谁。

说到点子上了
其实function(){
...
this ..
}
是一个过程的“模板”
谁都可以用这个“模板”
this就是代表这个“谁”
11 楼 cherami 2007-05-08  
呵呵,Java参数传递类型的问题似乎又传递到JavaScript了
10 楼 j2eeqk 2007-03-06  
这里顺便提提function(){}模拟[].
刚才jianfeng008cn中代码示意到this.length的变化,其实length只是obj对象的一个属性,和对象数组的length没有干系.
9 楼 j2eeqk 2007-03-06  
引用
function test() {  
    alert(this);  
}  
test.call();  
test.call("String Object");


这种理解方案很好~不过这篇帖子我建议不需要太过于仔细的去理解了。因为是真的把简单的问题弄复杂了。
其实很简单。在function(){}中引入this是一个动态的变量。谁去调就指向谁。这点和java语言是不相同的。这也正是javascript的魅力所在。不过一般象上面我引用的示例代码中在call中第一个函数传递串的还很少见。一般都是传对象,取代test类内部的this。不过如果确实是
引用
test.call("String Object");
那么
引用
alert( this.constructor );
你可以发现是String,这不奇怪,但
引用
alert( typeof this );
你会发现是Object,即js解析器会new出一个内存空间来。相当于
引用
test.call( new String( "XXXX" ) )
8 楼 flyingis 2006-10-01  
jianfeng008cn 写道

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


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

element.onclick = doSomething;   // Y方案



纠正的极是
7 楼 jianfeng008cn 2006-09-30  
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





function showName(name){
  alert("name:"+name);
}
var obj = new Object();
obj.fun=showName;
obj.fun("jianfeng008cn");
delete obj.fun;




function test() {
    alert(this);
}
test.call();
test.call("String Object");


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

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


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

element.onclick = doSomething;   // Y方案








5 楼 Readonly 2006-09-29  
这个文章把简单的东东讲复杂了,在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
4 楼 LucasLee 2006-09-29  
脚本语言看似简单,用起来实际还挺复杂。
只是把复杂性推迟了而没有隐藏。
3 楼 flyingis 2006-09-28  
@jianfeng008cn
感谢精彩回复。

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

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

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

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


上面两种方案的差别在于,X方案是在onclick的匿名函数中去调用doSomething(),Y方案中是将onclick指向了doSomething(),因此在doSomething()中使用this,其含义就产生了差别。在X方案中,如果显式的将this作为doSomething的参数传入,this自然就指向了onclick所属的HTML元素,得到我们所需要的结果。
2 楼 jianfeng008cn 2006-09-19  
主题:"this" of JavaScript [翻译] 
链接:http://www.iteye.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对象的属性改变只是他指向了内存中重新生成的一个对象,原来的所指向的内存中的那个对象并没有改变。当然这一说法针对的是属性为对象类型

下面我附上一个例子:
function MakeArray(n) {
	this[0] = "anuary"
	this[1] = "February"
	this[2] = "March"
	this[3] = "April"
	this[4] = "May"
	this[5] = "June"
	this[6] = "July"
	this[7] = "August"
	this[8] = "September"
	this[9] = "October"
	this[10] = "November"
	this[11] = "December"
	this['length'] = n
	return this
}

theMonths = new Object();
theMonths.fun=MakeArray;
//这里打印出来看看也是有目的的哦
for(var p in theMonths){
    alert("property:" + p + "==>value:" + theMonths[p]);
}
theMonths.fun(12);

var p2 = new Object();
for(var p in theMonths ){
  p2[p]=theMonths[p];
}
//先打印一遍
for(var p in theMonths){
    alert("property:" + p + "==>value:" + theMonths[p]);
}
for(var p in p2){
    alert("property:" + p + "==>value:" + p2[p]);
}


theMonths.length=100;

//再印一遍 要理解为什么我会这样打印2遍哦
for(var p in theMonths){
    alert("property:" + p + "==>value:" + theMonths[p]);
}
for(var p in p2){
    alert("property:" + p + "==>value:" + p2[p]);
}

引用

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(内联事件注册)这样的处理方式有弊端,其实不然,这样做给了我们充分的自由,在触发了元素的事件以后,我们可以选择该处理什么范围内的事情,是全局还是针对该元素 控制权在我们自己手中。
1 楼 flyingis 2006-09-15  
翻译不准确的地方请大家指正

相关推荐

    火车头谷歌翻译插件火车头谷歌翻译插件

    【火车头谷歌翻译插件】是一款专为网络爬虫工具“火车头”设计的辅助插件,它能够帮助用户在抓取和处理网页数据时实现快速、准确的多语言翻译。这款插件集成了谷歌翻译的强大功能,为用户提供了一种方便的方式,将非...

    英语自动翻译(vb.net源代码)-第三版(bing翻译+google翻译)

    原理:利用Bing+Google翻译引擎. 使用方法,启动自动翻译后.右键复制需要翻译的英语文本(例如msdn英文文档),则将内容自动翻译出来. 1,速度更快,占用内存极小,采用多线程技术 2,采用谷歌+bing翻译api 程序需要翻译key...

    多语言自动翻译脚本 中文翻译英文 python 自动翻译

    多语言自动翻译脚本,支持多语言,中英文自动翻译脚本 python C:\Users\ganwang\Desktop\打车报销票\translatetools.py 请输入翻译文件地址:C:\Users\ganwang\Desktop\打车报销票\紫金集团DHR项目-多语言翻译_...

    C#调用微软在线翻译API实现简单的翻译功能

    ### C#调用微软在线翻译API实现简单的翻译功能 #### 技术背景与应用场景 随着全球化的加速发展,跨语言沟通的需求日益增加。无论是个人用户还是企业级应用,都需要高效、准确的语言转换工具来打破语言障碍。在此...

    【语音翻译+机器翻译+语音合成】在线实时语音翻译

    本项目实现了一套快速有效的语音中英翻译系统,该系统可实现高精度的语音识别、高效双语翻译以及精准的语音合成,可应用于实时翻译场景。系统预先要求用户设置翻译模式,当用户说话时系统进行自动识别及实时翻译,...

    C# Winform开发的英语词典,调用了Google翻译、百度翻译、金山词霸、海词翻译等接口

    这个项目结合了Google翻译、百度翻译、金山词霸和海词翻译等流行的服务,为用户提供多源词汇查询和翻译的功能,从而提高学习和工作的效率。 首先,C#是一种面向对象的编程语言,由微软公司开发,它被广泛用于构建...

    工具Google翻译修复工具-1.3

    【工具】Google翻译修复工具_1.3 能一键修复GooLe翻译,原理很简单,通过修改Goole翻译指向IP,达到访问正常的目的,实测是IDEA翻译插件可用。 使用方法: 1. 先点击“检测”,测试本机是否链接Google正常,如果正常...

    基于谷歌、百度、腾讯等翻译接口的翻译实现源码

    【标题】:“基于谷歌、百度、腾讯等翻译接口的翻译实现源码” 在这个项目中,开发者集成了一系列主流的在线翻译API,包括谷歌翻译、百度翻译、腾讯翻译等,旨在提供一个方便的多语言翻译工具。这个工具的核心是...

    知云文献翻译 Mac-108 苹果电脑版 macOS版 文献 论文 pdf 翻译

    知云文献翻译是一款专为苹果Mac用户设计的高效文献翻译工具,特别适用于进行毕业设计、学术研究等需要大量阅读PDF文献的场景。该软件能够帮助用户快速理解和掌握外语论文的内容,提升科研工作的效率。 在Mac操作...

    【精品小工具】Ali智能图片翻译工具,免费版 这是个图片-图片的翻译工具,可以翻译本地和在线图片 可以批量

    Ali智能图片翻译工具,免费版。这是个图片--图片的翻译工具,可以翻译本地和在线图片。可以批量。 本软件使用阿里云的图片翻译接口。 阿里云提供了图片翻译功能,也就是输入中文/英文图片,返回英文或者其它语言的...

    Qt5翻译源码翻译文件(解决QTextEdit没有翻译的版本)

    Qt翻译源码翻译文件(解决QTextEdit没有翻译的版本) // Qt中文翻译 QTranslator qtTranslator; { QDir dir(qApp-&gt;applicationDirPath() + "/translations"); dir.setFilter(QDir::Files | QDir::Hidden | QDir:...

    java中英文翻译---调用Google翻译API

    Java编程语言在实际应用中经常会遇到需要处理多语言文本的情况,比如进行中英文翻译。在本项目中,我们将探讨如何利用Google的翻译API在Java环境中实现这一功能。标题"java中英文翻译---调用Google翻译API"明确指出...

    firefox翻译插件

    标题 "Firefox翻译插件" 指的是在Mozilla Firefox浏览器中使用的扩展程序,这些插件旨在帮助用户方便地翻译网页内容。Firefox是一个开源且高度可定制的网络浏览器,其丰富的扩展库是它的一大特色。"quick-translator...

    js利用google翻译接口把网页翻译成各国语言

    ### JavaScript 实现网页内容通过Google翻译接口转换为多种语言 #### 概述 在现代互联网应用中,国际化和多语言支持对于吸引全球用户至关重要。利用JavaScript(简称JS)结合Google翻译API可以实现在网页上自动...

    在线翻译器源代码

    在线翻译器源代码是开发一款能够实现在网页上翻译多种语言的应用程序的代码基础。这个项目使用了C语言编写,这是一种广泛应用于系统编程、嵌入式系统和高性能计算等领域的编程语言。C语言以其高效、灵活和直接访问...

    python离线翻译器.zip

    Python离线翻译器是一款基于Python开发的实用工具,它提供了英文到中文以及中文到英文的翻译功能,无需网络连接即可使用。这款翻译器的核心特点在于其离线特性,这意味着用户在没有WiFi或其他网络连接的情况下也能...

    最新谷歌翻译工具.zip

    《最新谷歌翻译工具详解》 谷歌翻译(Google Translate)是全球知名的在线翻译服务,由谷歌公司提供,支持多种语言间的互译,广泛应用于个人、教育和商业领域。本篇文章将详细解析一款基于C#实现的最新谷歌翻译工具...

    中英文翻译数据集百万数据集合

    中英文翻译数据集百万数据集合中英文翻译数据集百万数据集合中英文翻译数据集百万数据集合中英文翻译数据集百万数据集合中英文翻译数据集百万数据集合中英文翻译数据集百万数据集合中英文翻译数据集百万数据集合中...

    谷歌翻译插件无法翻译修复版v2.0.8

    谷歌翻译插件是许多用户在浏览网页时进行跨语言沟通的重要工具,尤其对于那些需要频繁接触多语言内容的用户来说,它的存在极大地提高了工作效率。然而,有时候用户可能会遇到谷歌翻译插件无法正常工作的问题,这可能...

    免费文档翻译软件中英翻译语言翻译

    在IT领域,文档翻译软件是专业人士和普通用户处理多语言文档时不可或缺的工具。本文将深入探讨“免费文档翻译软件中英翻译语言翻译”这一主题,解析其核心功能和技术,并提供一些实用技巧。 首先,标题提到的“免费...

Global site tag (gtag.js) - Google Analytics