js函数绑定同时,如何保留代码执行环境?
2015-04-07 23:43
316 查看
经常写js的程序员一定不会对下面这段代码感到陌生。
这段代码可以用跨浏览器的方式给元素绑定事件处理函数。
像这样:
这样做的话,alert框中显示的不是“bind me”,而是undefined。这是因为没有保存handler.handleClick的环境,即handleClick 中的this并没有指向handler类。
一般情况下,这样做也没有什么问题。但在某些需要保存代码的执行环境的情况下,比如说,事件处理函数、setTimeout()等。在这些情况下,我们可能会需要利用原来执行环境中的某些变量,状态标识等信息。
比较容易想到的一种解决方法是使用闭包。
就像这样:
但是,闭包用多了会让代码变得难以维护。
于是翻阅资料,发现一个常用的函数
是的,这个函数也使用了闭包,但是这个bind函数还是很强大的,它可以将我们的函数fn,绑定到我们制定的执行环境context中。这个bind函数还是比较好理解的。那么,可以这样来使用它。
注意这句 fn.apply(context, arguments); 这样可以保证事件对象e也传递给了fn。
令人庆幸的是,在ECMAScript5中,所有函数都定义一个原生的bind函数,我们可以直接来使用它。
值得注意的是,IE9+、ff4+,chrome支持这个bind函数。
最近在看一个开源项目的源码时,发现了一个更好的方法,这个方法不仅能解决上述问题,还能提供更好的事件管理方案。
这个方法就是
addEventListener + handleEvent
首先,我们来看看addEventListener的参数都有哪些,
parameters:
1. type of type DOMString
The event type for which the user is registering
用户注册的事件类型
2.listener of type EventListener
The listener parameter takes an interface implemented by the user which contains the methods to be called when the event occurs.
listener是用户定义的一个EventListener接口的实现,事件发生时会被调用。(这里是重点)
3.useCapture of type boolean
定义事件在哪个阶段被处理,一般都是false,即在冒泡阶段处理事件。
再来看看,EventListener这个接口,
官方对handleEvent的解释是
This method is called whenever an event occurs of the type for which the
就是说,在事件发生被处理时,这个函数会被调用,evt就是事件对象。
看来addEventListener的第二个参数,不仅支持传入一个回调函数,还可以传入一个对象,前提是这个对象中实现了handleEvent方法。利用这个特性,可以这样来使用:
这样一来,不用当心函数的执行环境被改变。
这个方法还有一个更大的用处就是可以创作一个事件管理中心来更方便,更优雅地管理事件。
像这样:
handler类中的handleEvent方法就是一个事件中心,通过事件的类型,来决定采用哪种处理逻辑。是不是很方便。
注意:这个接口属于DOM2,所以只能在IE9+,ff,chrome等浏览器中使用。
参考资料
1.《JavaScript高级程序设计》
2.http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventListener
3.http://www.tuicool.com/articles/uIfeM3V
var EventUtil = { addHandler : function(element, type, handler){ if(element.addEventListener){ element.addEventListener(type, handler, false); }else if(element.attachEvent){ element.attachEvent("on"+type,handler); }else{ element["on"+type]=handler; } }, removeHandler : function(element, type, handler){ if(element.removeEventListener){ element.removeEventListener(type, handler, false); }else if(element.detachEvent){ element.detachEvent("on"+type, handler); }else{ element["on"+type]=null; } } } ;
这段代码可以用跨浏览器的方式给元素绑定事件处理函数。
像这样:
var handler = { info : "bind me", handleClick : function(e){ alert(this.info); } } var btn = document.getElementById("mybtn");//一个按钮 EventUtil.addHandler( btn, "click", handler.handleClick);
这样做的话,alert框中显示的不是“bind me”,而是undefined。这是因为没有保存handler.handleClick的环境,即handleClick 中的this并没有指向handler类。
一般情况下,这样做也没有什么问题。但在某些需要保存代码的执行环境的情况下,比如说,事件处理函数、setTimeout()等。在这些情况下,我们可能会需要利用原来执行环境中的某些变量,状态标识等信息。
比较容易想到的一种解决方法是使用闭包。
就像这样:
var handler = { info : "bind me", handleClick : function(e){ alert(this.info); } } var btn = document.getElementById("mybtn");//一个按钮 EventUtil.addHandler( btn, "click", function(e){ handler.handleClick(e); });
但是,闭包用多了会让代码变得难以维护。
于是翻阅资料,发现一个常用的函数
function bind(fn, context){ return function(){ return fn.apply(context, arguments); } }
是的,这个函数也使用了闭包,但是这个bind函数还是很强大的,它可以将我们的函数fn,绑定到我们制定的执行环境context中。这个bind函数还是比较好理解的。那么,可以这样来使用它。
var handler = { info : "bind me", handleClick : function(e){ alert(this.info); } } var btn = document.getElementById("mybtn");//一个按钮 EventUtil.addHandler( btn, "click", bind(handler.handleClick, handler));
注意这句 fn.apply(context, arguments); 这样可以保证事件对象e也传递给了fn。
令人庆幸的是,在ECMAScript5中,所有函数都定义一个原生的bind函数,我们可以直接来使用它。
var handler = { info : "bind me", handleClick : function(e){ alert(this.info+" "+e.type); } } var btn = document.getElementById("mybtn");//一个按钮 EventUtil.addHandler( btn, "click", handler.handleClick.bind(handler));
值得注意的是,IE9+、ff4+,chrome支持这个bind函数。
最近在看一个开源项目的源码时,发现了一个更好的方法,这个方法不仅能解决上述问题,还能提供更好的事件管理方案。
这个方法就是
addEventListener + handleEvent
首先,我们来看看addEventListener的参数都有哪些,
parameters:
1. type of type DOMString
The event type for which the user is registering
用户注册的事件类型
2.listener of type EventListener
The listener parameter takes an interface implemented by the user which contains the methods to be called when the event occurs.
listener是用户定义的一个EventListener接口的实现,事件发生时会被调用。(这里是重点)
3.useCapture of type boolean
定义事件在哪个阶段被处理,一般都是false,即在冒泡阶段处理事件。
再来看看,EventListener这个接口,
// Introduced in DOM Level 2: interface EventListener { void handleEvent(in Event evt); };
官方对handleEvent的解释是
This method is called whenever an event occurs of the type for which the
EventListenerinterface was registered.
就是说,在事件发生被处理时,这个函数会被调用,evt就是事件对象。
看来addEventListener的第二个参数,不仅支持传入一个回调函数,还可以传入一个对象,前提是这个对象中实现了handleEvent方法。利用这个特性,可以这样来使用:
var handler = { info : "bind me", handleEvent : function(e){ alert(this.info+" "+e.type); } } var btn = document.getElementById("mybtn");//一个按钮 EventUtil.addHandler( btn, "click", handler);
这样一来,不用当心函数的执行环境被改变。
这个方法还有一个更大的用处就是可以创作一个事件管理中心来更方便,更优雅地管理事件。
像这样:
var handler = { info : "bind me", handleEvent : function(e){ switch(e.type){ case "mousedown": this.startHandle(e); break; case "mousemove": this.moveHandle(e); break; case "mouseup": this.endHandle(e); break; default: //todo } }, startHandle:function(e){ //todo }, moveHandle:function(e){ //todo }, endHandle:function(e){ //todo } } var btn = document.getElementById("mybtn");//一个按钮 EventUtil.addHandler( btn, "mousedown", handler);
handler类中的handleEvent方法就是一个事件中心,通过事件的类型,来决定采用哪种处理逻辑。是不是很方便。
注意:这个接口属于DOM2,所以只能在IE9+,ff,chrome等浏览器中使用。
参考资料
1.《JavaScript高级程序设计》
2.http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventListener
3.http://www.tuicool.com/articles/uIfeM3V
相关文章推荐
- [error handle][java script]如何做到js绑定事件的同时不执行事件
- 如何做到js绑定事件的同时不执行事件
- 如何在后台CS代码文件中调用前台JS文件中的某一个函数
- 牛腩购物 8 整合用户留言 动软生成器 ,.NET在后置代码中输入JS提示语句(背景不会变白),repeater 循环的时候事件判断,repeater 隔行 奇数行,item列,隐藏区块 Panel 的使用,前台绑定代码的时候使用函数
- js如何执行函数
- js Function对象扩展与延时执行函数实例代码
- js如何实现一定时间后去执行一个函数
- JS 事件绑定函数代码
- js查看一个函数的执行时间实例代码
- javascript笔记——点击按钮(或超链接)如何跳转到另外一个页面并执行目标页面的js函数
- 如何确保页面中的js加载完全后再执行其他代码
- FineUI如何在后台代码中执行JS
- 如何在net中实现动态执行代码(js的eval)的功能?
- js查看一个函数的执行时间实例代码
- js 函数的执行环境和作用域链的深入解析
- 在.NET(Java也适用的)环境下,如何执行字符串所代表方法名(函数名)
- ...后台代码中如何调用 javascript 函数的问题! - ASP.NET专题(按钮事件中调用JS文件中函数)
- ...后台代码中如何调用 javascript 函数的问题! - ASP.NET专题(按钮事件中调用JS文件中函数)
- cocos2d-js 安卓环境,如何用js代码直接调用java函数
- 立即执行函数表达式 项目经常用到js 代码Module模式