『求教』关于javascript中this的疑问(JavaScript DOM高级程序设计addEvent函数)

溺水的鱼 2009-08-17 07:37:55
function addEvent( node, type, listener ) {
// Check compatibility using the earlier method
// to ensure graceful degradation
if(!isCompatible()) { return false }
if(!(node = $(node))) return false;

if (node.addEventListener) {
// W3C method
node.addEventListener( type, listener, false );
return true;
} else if(node.attachEvent) {
// MSIE method
node['e'+type+listener] = listener;
node[type+listener] = function(){node['e'+type+listener]( window.event );}
node.attachEvent( 'on'+type, node[type+listener] );
return true;
}

// Didn't have either so return false
return false;
};

这个函数里面关于IE绑定事件的部分,不太明白为什么这样处理之后,事件的上下文(也就是this关键字)就是函数绑定的元素(也就是node)了,请高手给指点下。
...全文
254 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
dh20156 2009-08-18
  • 打赏
  • 举报
回复
this始终指向调用它的对象!
溺水的鱼 2009-08-18
  • 打赏
  • 举报
回复
还是没有搞明白,为什么this指node
。。。太郁闷了
高手给点化一下吧
溺水的鱼 2009-08-18
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 hookee 的回复:]
如果写在标签内 <div onclick="xxx()">
对于此div相当于this.onclick=xxx;
现在通过函数addEvent(node,'click',xxx) 绑定处理函数时
node是以上的div的话node.attachEvent()就实现了this.onclick=xxx;
---------------------
原函数中并不是直接this.onclick=xxx而是转了个弯,至于为什么,上面已经解释了。
他把处理函数句柄赋值给this(node)的属性,node['xxx']=node.xxx= xxxx
然后再this.onclick = node.xxx 相当于this.onclick=node.xxx=xxx
通过转换多加了个参数而已.

[/Quote]
node是以上的div的话node.attachEvent()就实现了this.onclick=xxx;
虽然实现了,但是内部的this是不同的,通过this.onclcik=xxx;那么xxx函数内部的this就是指这个div,但是通过node.attatchEvent绑定函数xxx,则xxx内部使用的this就不是div了

=================
下面的内容我还得消化一下,多谢指点
hookee 2009-08-18
  • 打赏
  • 举报
回复
如果写在标签内 <div onclick="xxx()">
对于此div相当于this.onclick=xxx;
现在通过函数addEvent(node,'click',xxx) 绑定处理函数时
node是以上的div的话node.attachEvent()就实现了this.onclick=xxx;
---------------------
原函数中并不是直接this.onclick=xxx而是转了个弯,至于为什么,上面已经解释了。
他把处理函数句柄赋值给this(node)的属性,node['xxx']=node.xxx= xxxx
然后再this.onclick = node.xxx 相当于this.onclick=node.xxx=xxx
通过转换多加了个参数而已.
溺水的鱼 2009-08-18
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 net_lover 的回复:]
this指对象本身
[/Quote]
您能不能说的具体些
溺水的鱼 2009-08-18
  • 打赏
  • 举报
回复
通过使用匿名函数使this关键字在Microsoft和W3C的环境中保持一致,其中this引用的是将侦听器指派给的对象。

==========================
这个是书中的原话。
溺水的鱼 2009-08-18
  • 打赏
  • 举报
回复
谢谢大家的回答,但是我问的是为什么:事件的上下文(也就是this关键字)就是函数绑定的元素(也就是node)了


也就是如果在处理函数内部调用this.xxx===node.xxx

书上是这么说的,但是我不太明白为什么这样
溺水的鱼 2009-08-18
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 toury 的回复:]
看看这样给你注释一下是否有帮助。HTML code<html><head><title>ADS.addEvent</title><scripttype="text/javascript">debugger;/**
* document.getElementById(); replacement.*/function $() {var elements=new Array();// Find all the elements supplied as argumentsfor (var i=0; i< arguments.length; i++) {var element= arguments[i];// If the argument is a string assume it's an idif (typeof element=='string') {
element= document.getElementById(element);
}// If only one argument was supplied, return the element immediatelyif (arguments.length==1) {return element;
}// Otherwise add it to the array elements.push(element);
}// Return the array of multiple requested elementsreturn elements;
};/**
* Register an event listener on an element*/function addEvent(node, type, listener ) {// Check compatibility using the earlier method// to ensure graceful degradationif(!(node= $(node)))returnfalse;if (node.addEventListener) {// W3C method node.addEventListener( type, listener,false );returntrue;
}elseif(node.attachEvent) {// MSIE methodif(node.id=='windowid'){alert('宿主依然是window')}else{alert('注意:宿主变成了传入的对象')}var fn='e'+type+listener;//定义一个新对象 node[fn]= listener;//将参数(clickHandler数)赋值给调用的宿主alert(node[fn])

node[type+listener]=function(){node[fn]( window.event );}//注意:第一次执行addEvent(this/*这个this是指window*/,'load', function(){...},//开始侦听onload事件,准备addEvent($('btnTest'),'click',clickHandler);
node.attachEvent('on'+type, node[type+listener] );returntrue;
}// Didn't have either so return falsereturnfalse;
};function clickHandler(){
alert("this.name:"+this.name+"\nthis.type:"+this.type+'\nthis.id:'+this.id+'\nthis.value:'+this.value);
}//这段js执行顺序:name='clickHandlerName';//1type='windowtype';//2id='windowid';//3value='windowvalue';//4
addEvent(this/*这个this是指window*/,'load',function(){//5 addEvent($('btnTest'),'click',clickHandler);//7!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//用自定义方法向节点$('btnTest')添加事件//对象:$('btnTest')按钮1//事件:click//通过两次addEvent()将调用对象从window转变为$('btnTest')! }
);

addEvent(window,'load',function(){//6 $('btnTest1').attachEvent('onclick',clickHandler);//用IE默认的attachEvent方法添加事件});</script></head><body><inputname="btnTest" id="btnTest" type="button" value="按钮1"/><br/><inputname="btnTest1" id="btnTest1" type="button" value="按钮2"/></body></html>
[/Quote]

多谢多谢,终于搞明白了!
function(){node['e'+type+listener]( window.event );}
这里面等于直接调用node.xxxListener(param);
上下文当然就是node了。。。
唉。。太笨了。。。
再次感谢大家不厌其烦的解答!
toury 2009-08-18
  • 打赏
  • 举报
回复
看看这样给你注释一下是否有帮助。

<html>
<head>
<title>ADS.addEvent </title>
<script type="text/javascript">
debugger;
/**
* document.getElementById(); replacement.
*/
function $() {
var elements = new Array();

// Find all the elements supplied as arguments
for (var i = 0; i < arguments.length; i++) {
var element = arguments[i];

// If the argument is a string assume it's an id
if (typeof element == 'string') {
element = document.getElementById(element);
}

// If only one argument was supplied, return the element immediately
if (arguments.length == 1) {
return element;
}

// Otherwise add it to the array
elements.push(element);
}

// Return the array of multiple requested elements
return elements;
};

/**
* Register an event listener on an element
*/
function addEvent(node, type, listener ) {
// Check compatibility using the earlier method
// to ensure graceful degradation
if(!(node = $(node))) return false;

if (node.addEventListener) {
// W3C method
node.addEventListener( type, listener, false );
return true;
} else if(node.attachEvent) {
// MSIE method
if(node.id=='windowid'){alert('宿主依然是window')}
else{alert('注意:宿主变成了传入的对象')}
var fn='e'+type+listener;//定义一个新对象
node[fn] = listener;//将参数(clickHandler数)赋值给调用的宿主
alert(node[fn])

node[type+listener] = function(){node[fn]( window.event );}
//注意:第一次执行addEvent(this/*这个this是指window*/,'load', function(){...},
//开始侦听onload事件,准备addEvent($('btnTest'),'click',clickHandler);

node.attachEvent( 'on'+type, node[type+listener] );
return true;
}

// Didn't have either so return false
return false;
};

function clickHandler(){
alert("this.name: "+this.name + "\nthis.type: "+this.type + '\nthis.id: ' + this.id + '\nthis.value: ' + this.value);
}

//这段js执行顺序:
name='clickHandlerName';//1
type='windowtype';//2
id='windowid';//3
value='windowvalue';//4

addEvent(this/*这个this是指window*/,'load', function(){//5
addEvent($('btnTest'),'click',clickHandler);//7!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//用自定义方法向节点$('btnTest')添加事件
//对象:$('btnTest')按钮1
//事件:click
//通过两次addEvent()将调用对象从window转变为$('btnTest')!
}
);

addEvent(window,'load',function(){//6
$('btnTest1').attachEvent('onclick',clickHandler);
//用IE默认的attachEvent方法添加事件
});
</script>
</head>
<body>
<input name="btnTest" id="btnTest" type="button" value="按钮1" />
<br/>
<input name="btnTest1" id="btnTest1" type="button" value="按钮2" />
</body>
</html>

溺水的鱼 2009-08-18
  • 打赏
  • 举报
回复
郁闷。。。第二天了
溺水的鱼 2009-08-18
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 toury 的回复:]
你先把this整明白再搞attachEvent, detachEvent, addEventListener, and removeEventListener 函数吧;
先学走后学跑,不然摔跤
[/Quote]

node['e'+type+listener] = listener;
node[type+listener] = function(){node['e'+type+listener]( window.event );}
node.attachEvent( 'on'+type, node[type+listener] );

这段代码如何实现绑定之后,this指向真正调用它的对象,能给解释一下吗,拜托了
溺水的鱼 2009-08-18
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 hotup 的回复:]
attachEvent 的缺点,绑定函数内this指向的是window,
[/Quote]

恩,所以这个方案(addEvent)解决了这个问题,让IE的attachEvent绑定函数内this指向真正调用它的对象
可就是高不明白为什么
node['e'+type+listener] = listener;
node[type+listener] = function(){node['e'+type+listener]( window.event );}
node.attachEvent( 'on'+type, node[type+listener] );
这样处理之后就可以了
hotup 2009-08-18
  • 打赏
  • 举报
回复
attachEvent 的缺点,绑定函数内this指向的是window,
toury 2009-08-18
  • 打赏
  • 举报
回复
你先把this整明白再搞attachEvent, detachEvent, addEventListener, and removeEventListener 函数吧;
先学走后学跑,不然摔跤
溺水的鱼 2009-08-18
  • 打赏
  • 举报
回复
This is the project page for my entry into the addEvent() recoding contest. It works in all of the modern browsers: Windows IE 5+, Mozilla, Opera, and Safari. The code meets every item outlined in the guideline - attempting to be as short and simple as possible. You can view a demo of it in action.

This library consists of two functions: addEvent and removeEvent. To use them, simply copy the code from below, paste it into your Javascript code, and call it using these methods:

addEvent( object, eventType, function );

The 'object' parameter should be the object upon which you want the event to be called.
The 'eventType' parameter should hold the name of the event, for example: 'click', 'mouseover', 'load', 'submit', etc. More can be found here.
The 'function' parameter should be a reference to a function that you wish to have called whenever the event fires. One parameter will be passed to 'function' - the event object.

Some examples of addEvent in use:

addEvent( document.getElementById('foo'), 'click', doSomething );
addEvent( obj, 'mouseover', function(){ alert('hello!'); } );

removeEvent( object, eventType, function );

removeEvent is virtually identical to addEvent, with the obvious difference: Instead of the function being added to the event handler, it is removed instead. All of the above code and parameters applies to this function.

The code, itself, is very short and simple - only 15 lines long:

1. function addEvent( obj, type, fn ) {
2. if ( obj.attachEvent ) {
3. obj['e'+type+fn] = fn;
4. obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
5. obj.attachEvent( 'on'+type, obj[type+fn] );
6. } else
7. obj.addEventListener( type, fn, false );
8. }
9. function removeEvent( obj, type, fn ) {
10. if ( obj.detachEvent ) {
11. obj.detachEvent( 'on'+type, obj[type+fn] );
12. obj[type+fn] = null;
13. } else
14. obj.removeEventListener( type, fn, false );
15. }

Much of the above code is trying to fix a serious problem with Internet Explorer. The code has to be this troublesome due to the fact that when your attached function gets fired, the 'this' reference refers to the worthless 'window', when, in fact, it should refer to the parent object. An explanation of the key points:

obj['e'+type+fn] = fn;

This makes the function a child of the specified object. The key, which is placed in the object hash, is (hopefully) unique and won't collide with any other function additions.

obj[type+fn] = function(){ obj['e'+type+fn]( window.event ); }

This line creates an anonymous function who, once executed, will fire the previously attached function - passing it the global event object. This whole function is being attached to the object so that it can be removed later, using the removeEvent() function.

Finally, for more information on the attachEvent, detachEvent, addEventListener, and removeEventListener functions - please refer to the excellent resource at Quirksmode.

-----------------
谁能看明白
toury 2009-08-18
  • 打赏
  • 举报
回复

<html>
<head>
<style>
#p{position:absolute;border:1px solid;width:500px;height:400px;background:blue;}
#c1{position:absolute;border:1px solid;width:100px;height:200px;top:50px;left:10px;background:yellow; float:left}
#c2{position:absolute;border:1px solid;width:100px;height:200px;top:50px;left:150px;background:yellow; float:left}
</style>
</head>
<body>
<div id=p>父节点
<div id=c1>子节点1</div>
<div>

</body>
</html>
<script>
var pNode=document.getElementById("p")
var c1Node=document.getElementById("c1")
var newNode=document.createElement("DIV");
newNode.setAttribute("id","c2")
newNode.setAttribute("innerHTML","子节点2")
pNode.appendChild(newNode)

var c2Node=document.getElementById("c2")
c2Node.innerHTML="子节点2<br><br>点击我"
/*****************THIS*******************/
c2Node.onclick=function(){
alert(this.id)
this.innerHTML ="子节点2<br><br>[this.innerHTML]中的this指的就是我<br><br>现在点击左边的黄色块"
c1Node.onclick=function(){
alert(this.id)
this.innerHTML ="子节点1<br><br>[this.innerHTML]中的this指的就是子节点1,也就是我。因为是对象c1Node(子节点1)调用的onclick";

}
}

</script>

溺水的鱼 2009-08-18
  • 打赏
  • 举报
回复
<html>
<head>
<title>ADS.addEvent</title>
<script type="text/javascript">
/**
* document.getElementById(); replacement.
*/
function $() {
var elements = new Array();

// Find all the elements supplied as arguments
for (var i = 0; i < arguments.length; i++) {
var element = arguments[i];

// If the argument is a string assume it's an id
if (typeof element == 'string') {
element = document.getElementById(element);
}

// If only one argument was supplied, return the element immediately
if (arguments.length == 1) {
return element;
}

// Otherwise add it to the array
elements.push(element);
}

// Return the array of multiple requested elements
return elements;
};

/**
* Register an event listener on an element
*/
function addEvent( node, type, listener ) {
// Check compatibility using the earlier method
// to ensure graceful degradation
if(!(node = $(node))) return false;

if (node.addEventListener) {
// W3C method
node.addEventListener( type, listener, false );
return true;
} else if(node.attachEvent) {
// MSIE method
node['e'+type+listener] = listener;
node[type+listener] = function(){node['e'+type+listener]( window.event );}
node.attachEvent( 'on'+type, node[type+listener] );
return true;
}

// Didn't have either so return false
return false;
};

function clickHandler(){
alert(this.name + '-' + this.type + '-' + this.id + '-' + this.value);
}

window.name='clickHandlerName';
window.type='windowtype';
window.id='windowid';
window.value='windowvalue';

addEvent(window,'load',function(){
var el = $('btnTest');
addEvent(el,'click',clickHandler);
});

addEvent(window,'load',function(){
var el = $('btnTest1');
el.attachEvent('onclick',clickHandler);
});
</script>
</head>
<body>
<input name="btnTest" id="btnTest" type="button" value="click" />
<br/>
<input name="btnTest1" id="btnTest1" type="button" value="click1" />
</body>
</html>

运行一下,直接用ie的绑定事件方法(attachEvent)绑定处理函数(clickHandler)之后,处理函数内部的this表示的是window对象,但是经过addEvent里面那样处理之后就变为要绑定的对象了。

不要再说 ---this始终指向调用它的对象!

这样说真的不明白,能具体点吗
浴火_凤凰 2009-08-17
  • 打赏
  • 举报
回复
为了与ff兼容。共用事件处理函数
hookee 2009-08-17
  • 打赏
  • 举报
回复
node['e'+type+listener] = listener;
node[type+listener] = function(){node['e'+type+listener]( window.event );}
node.attachEvent( 'on'+type, node[type+listener] );
相当于直接
node.attachEvent( 'on'+type, function(){listener(event)});

listener是处理函数
node['e'+type+listener] = listener; 等于 node.xxx = listener;
node[type+listener] = function(){node['e'+type+listener]( window.event );}
相当于 node.xxxx= listener(event);
------------------------------------
这样做是为了与ff兼容。共用事件处理函数,因为ff的事件处理函数是带一个事件参数的,而ie可以直接用全局的event,并不需要传,为了兼容,要传一个的话,就直接传event了.
孟子E章 2009-08-17
  • 打赏
  • 举报
回复
this指对象本身
加载更多回复(1)

87,901

社区成员

发帖
与我相关
我的任务
社区描述
Web 开发 JavaScript
社区管理员
  • JavaScript
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧