本文记录了 JavaScript 面向对象开发中遇到的三个核心问题:动态事件绑定的跨浏览器兼容、类方法中 this 指向丢失的解决方案,以及 IE 浏览器下 setInterval 不支持参数传递的兼容处理。通过封装 addEventHandler、Bind 函数及重写 window.setInterval,实现了代码在主流浏览器中的稳定运行。
JavaScript 封装类开发背景与问题概述
此前编写的代码多为分散的独立函数,即用到什么功能便编写什么函数,这种写法导致代码结构不够整洁。因此,本次尝试将功能封装为类,虽然整体使用体验良好,但在参数传递环节遇到了诸多阻碍。经过查阅大量资料,现将遇到的问题及解决方案总结如下:
动态事件绑定与 this 指向处理
1)动态绑定事件问题:
需要将 onclick 事件绑定到具体对象(如列表项)上。为此,需使用 addEventListener 或 attachEvent 将函数操作添加到事件中,而非覆盖原有事件。然而,attachEvent 不支持 Firefox 浏览器,Firefox 仅支持 addEventListener。因此,需要编写一个综合函数来兼容两者,该函数定义如下:
代码如下:
function addEventHandler(oTarget, sEventType, fnHandler)
{
if(oTarget.addEventListener)
{oTarget.addEventListener(sEventType, fnHandler, false);}
else if(oTarget.attachEvent)
{oTarget.attachEvent('on' + sEventType, fnHandler);}
else{oTarget['on' + sEventType] = fnHandler;}
} 2)传递 this 参数问题:
由于将函数和属性均封装在类中,在绑定 onclick 等事件时会出现 this 指向错误的问题。例如执行 addEventHandler(this.elems[i],"click",this.Move) 时会报错,因为在 onclick 事件触发时,this 不再指向该封装类。为此,需要利用 apply() 方法——即应用某一对象的一个方法,用另一个对象替换当前对象。具体格式此处省略,网络上已有大量说明。相关函数定义如下:
代码如下:
var Bind = function(object,func){
var args = Array.prototype.slice.call(arguments).slice(2);
return function(){
return func.apply(object,args);
}
} 调用:
this._fnMove=Bind(this,this.move,i);//this.move是我定义的一个成员函数,封装在类中
//this.elems[i].onclick=this._fnMove;//吧上面那句话换成这句话也是可以的,只不过,onclick事件就被替换为this._fnMove,而不是添加this._fnMove进去
addEventHandler(this.elems[i],"click",this._fnMove);
这样即可解决问题。
PS:call() 也具有基本相同的功能,但具体参数用法有所不同。
setInterval 在 IE 下的参数传递兼容方案
2.setInterval问题
1)与setTimeout的区别
通常情况下,setTimeout 仅执行一次(若在函数内反复调用 setTimeout 则可实现重复执行),而 setInterval 可以重复执行,直到调用 clearInterval() 停止。
2)在IE下不兼容问题
此问题耗费了我50%的时间,令人头疼的是,未来是否要花费半生精力与 IE 对抗?
代码在 Chrome、Firefox 和 Safari 上运行良好,令我相当激动,却因此忽略了 IE。在 IE 中测试时,代码完全无法工作。经过反复修改和搜索(此处为动词,嘿嘿),耗时大半天终于解决。此前代码为:this.timer=setInterval(this.unfold,5,this.divs[index],this),但在 IE 下无效。最终在某篇文章中发现:在 IE 下,setTimeout 和 setInterval 不支持参数传递。问题迅速解决,确实是我水平有限。
解决问题的函数如下:
代码如下:
var mySetInterval = setInterval;
window.setInterval = function(callback, interval)
{
var args = Array.prototype.slice.call(arguments, 2);
function callFn(){callback.apply(null, args);}
return mySetInterval(callFn, interval);
}
var mySetTimeOut = setTimeout; //修改setInterval
window.setTimeout = function(callback, timeout)
{
var args = Array.prototype.slice.call(arguments, 2);
function callFn(){callback.apply(null, args);} 然后使用window.setTimeout或window.setInterval调用就可以了~
我的语句修改如下:
this.timer=window.setInterval(this.unfold,5,this.divs[index],this); //其中,this.divs[index],this是传递的两个参数
再次感谢那位大侠,虽然他不认识我~
目前,在 IE 中还有点排版的小问题,继续学习~全力兔子!