首页 > 编程语言 >Javascript事件设计模式(七)

Javascript事件设计模式(七)

时间:2022-10-19 20:37:07浏览次数:79  
标签:function obj onShow Javascript cookie 事件 var 设计模式

一:事件设计概述
事件机制可以使程序逻辑更加符合现实世界,在JavaScript中很多对象都有自己的事件,例如按钮就有onclick事件,下拉列表框就有 onchange事件,通过这些事件可以方便编程。那么对于自己定义的类,是否也可以实现事件机制呢?是的,通过事件机制,可以将类设计为独立的模块,通过事件对外通信,提高了程序的开发效率。
二: 最简单的事件设计模式
最简单的一种模式是将一个类的方法成员定义为事件,这不需要任何特殊的语法,通常是一个空方法,例如:
function class1(){
//构造函数
}
class1.prototype={
show:function(){
//show函数的实现
this.onShow(); //触发onShow事件
},
onShow:function(){} //定义事件接口
}
上面的代码中,就定义了一个方法:show(),同时该方法中调用了onShow()方法,这个onShow()方法就是对外提供的事件接口,其用法如下:
//创建class1的实例
var obj=new class1();
//创建obj的onShow事件处理程序
obj.onShow=function(){
alert("onshow event");
}
//调用obj的show方法
obj.show();


由此可见,obj.onShow方法在类的外部被定义,而在类的内部方法show()中被调用,这就实现了事件机制。
上述方法很简单,实际的开发中常用来解决一些简单的事件功能。说它简单,因为它有以下两个缺点:
? 不能够给事件处理程序传递参数,因为是在show()这个内部方法中调用事件处理程序的,无法知道外部的参数;
? 每个事件接口仅能够绑定一个事件处理程序,而内部方法则可以使用attachEvent或者addEventListener方法绑定多个处理程序。
在下面两小节将着重解决这个问题。
三: 给事件处理程序传递参数
给事件处理程序传递参数不仅是自定义事件中存在的问题,也是系统内部对象的事件机制中存在的问题,因为事件机制仅传递一个函数的名称,不带有任何参数的信息,所以无法传递参数进去。例如:
//定义类class1
function class1(){
//构造函数
}
class1.prototype={
show:function(){
//show函数的实现
this.onShow(); //触发onShow事件
},
onShow:function(){} //定义事件接口
}
//创建class1的实例
var obj=new class1();
//创建obj的onShow事件处理程序
function obj.OnShow(userName){
alert("hello,"+userName);
}
//定义变量userName
var userName="jack";
//绑定obj的onShow事件
obj.onShow=objOnShow; //无法将userName这个变量传递进去
//调用obj的show方法
obj.show();
注意上面的obj.onShow=objOnShow事件绑定语句,不能为了传递userName变量进去而写成:
obj.onShow=objOnShow(userName);
或者:
obj.onShow="objOnShow(userName)";
前者是将objOnShow(userName)的运行结果赋给了obj.onShow,而后者是将字符串“objOnShow(userName)”赋给了obj.onShow。
要解决这个问题,可以从相反的思路去考虑,不考虑怎么把参数传进去,而是考虑如何构建一个无需参数的事件处理程序,该程序是根据有参数的事件处理程序创建的,是一个外层的封装。现在自定义一个通用的函数来实现这种功能:
//将有参数的函数封装为无参数的函数
function createFunction(obj,strFunc){
var args=[]; //定义args用于存储传递给事件处理程序的参数
if(!obj)obj=window; //如果是全局函数则obj=window;
//得到传递给事件处理程序的参数
for(var i=2;i<arguments.length;i++)args.push(arguments[i]);
//用无参数函数封装事件处理程序的调用
return function(){
obj[strFunc].apply(obj,args); //将参数传递给指定的事件处理程序
}
}
该方法将一个有参数的函数封装为一个无参数的函数,不仅对全局函数适用,作为对象方法存在的函数同样适用。该方法首先接收两个参数:obj和 strFunc,obj表示事件处理程序所在的对象;strFunc表示事件处理程序的名称。除此以外,程序中还利用arguments对象处理第二个参数以后的隐式参数,即未定义形参的参数,并在调用事件处理程序时将这些参数传递进去。例如一个事件处理程序是:
someObject.eventHandler=function(_arg1,_arg2){
//事件处理代码
}
应该调用:
createFunction(someObject,"eventHandler",arg1,arg2);


这就返回一个无参数的函数,在返回的函数中已经包括了传递进去的参数。如果是全局函数作为事件处理程序,事实上它是window对象的一个方法,所以可以传递window对象作为obj参数,为了更清晰一点,也可以指定obj为null,createFunction函数内部会自动认为该函数是全局函数,从而自动把obj赋值为window。下面来看应用的例子:

<script language="JavaScript" type="text/javascript">
<!--
<!--
//将有参数的函数封装为无参数的函数
function createFunction(obj,strFunc){
var args=[];
if(!obj)obj=window;
for(var i=2;i<arguments.length;i++)args.push(arguments[i]);
return function(){
obj[strFunc].apply(obj,args);
}
}
//定义类class1
function class1(){
//构造函数
}
class1.prototype={
show:function(){
//show函数的实现
this.onShow();//触发onShow事件
},
onShow:function(){}//定义事件接口
}
//创建class1的实例
var obj=new class1();
//创建obj的onShow事件处理程序
function objOnShow(userName){
alert("hello,"+userName);
}
//定义变量userName
var userName="jack";
//绑定obj的onShow事件
obj.onShow=createFunction(null,"objOnShow",userName);
//调用obj的show方法
obj.show();
//-->
</script>


在这段代码中,就将变量userName作为参数传递给了objOnShow事件处理程序。事实上,obj.onShow得到的事件处理程序并不是objOnShow,而是由createFunction返回的一个无参函数。
通过createFunction封装,就可以用一种通用的方案实现参数传递了。这不仅适用于自定义的事件,也适用于系统提供的事件,其原理是完全相同的。

前台代码:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
<script type="text/javascript" src="js/Core.js"></script>
<script type="text/javascript">
function Class01(){

}
Class01.prototype={
show:function(){
this.onShow();
},
onShow:function(){}
}
var userName="json";
var myOnshow=function(userName){
alert("hellow"+userName);
}
var myEventHandle2=function(usernaem,age){
alert(usernaem+","+age);
}

var class01=new Class01();
class01.onShow=createFunction(null,"myOnshow",userName);
class01.onShow=createFunction(null,"myEventHandle2","sunliyuan",20);

</script>
</head>
<body>
<button onclick="class01.show()">测试onShow事件</button>
</body>
</html>

 js代码:

function createFunction(obj,strFunc){
var args=[];
if(!obj)obj=window;
for(var i=2;i<arguments.length;i++)args.push(arguments[i]);
return function(){
obj[strFunc].apply(obj,args);
}
}

 四:使自定义事件支持多绑定

可以用attachEvent或者addEventListener方法来实现多个事件处理程序的同时绑定,不会互相冲突,而自定义事件怎样来实现多订阅呢?要实现多订阅,必定需要一个机制用于存储绑定的多个事件处理程序,在事件发生时同时调用这些事件处理程序。从而达到多订阅的效果,其实现如下:

<script language="JavaScript" type="text/javascript">
<!--
//定义类class1
function class1(){
//构造函数
}
//定义类成员
class1.prototype={
show:function(){
//show的代码
//...
//如果有事件绑定则循环onshow数组,触发该事件
if(this.onshow){
for(var i=0;i<this.onshow.length;i++){
this.onshow[i](); //调用事件处理程序
}
}
},
attachOnShow:function(_eHandler){
if(!this.onshow)this.onshow=[]; //用数组存储绑定的事件处理程序引用
this.onshow.push(_eHandler);
}
}
var obj=new class1();
//事件处理程序1
function onShow1(){
alert(1);
}
//事件处理程序2
function onShow2(){
alert(2);
}
//绑定两个事件处理程序
obj.attachOnShow(onShow1);
obj.attachOnShow(onShow2);
//调用show,触发onshow事件
obj.show();
//-->
</script>


从代码的执行结果可以看到,绑定的两个事件处理程序都得到了正确的运行。如果要绑定有参数的事件处理程序,只需加上createFunction方法即可,
这种机制基本上说明了处理多事件处理程序的基本思想,但还有改进的余地。例如如果类有多个事件,可以定义一个类似于attachEvent的方法,用于统一处理事件绑定。在添加了事件绑定后如果想删除,还可以定义一个detachEvent方法用于取消绑定。这些实现的基本思想都是对数组的操作。

代码:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
<script type="text/javascript" src="js/Core.js"></script>
<script type="text/javascript">
function Class01(){
}
Class01.prototype={
show:function(){
//如果有事件绑定循环onshow数组,触发该事件
if(this.onshow){
for(var i=0;i<this.onshow.length;i++){
this.onshow[i](); //调用事件处理程序
}
}
},
attachOnShow:function(_eHandler){
//用数组存储绑定的事件处理程序引用
if(!this.onshow)this.onshow=[];
this.onshow.push(_eHandler);

}
}

var class01=new Class01();

function onShow01(username){
alert("寿星:"+username);
}
function onShow02(username,birthday){
alert("寿星:"+username+"!!!!!二十岁"+ birthday);
}
var func1=createFunction(null,"onShow01","孙丽媛");
var func2=createFunction(null,"onShow02","孙丽媛","生日快乐:8月12日,难忘的一天");

class01.attachOnShow(func1);
class01.attachOnShow(func2);

</script>
</head>
<body>
<button onclick="class01.show()">生日快乐</button>
</body>
</html>


js代码:
function createFunction(obj,strFunc){
var args=[];
if(!obj)obj=window;
for(var i=2;i<arguments.length;i++)args.push(arguments[i]);
return function(){
obj[strFunc].apply(obj,args);
}
}

 

js面向对象的综合实例:
一:使用面向对象思想处理cookie
1.需求:
对于cookie的处理,事实上只是封装一些方法,每个对象不会有状态,所以不需要创建一个cookie处理类,而只用一个全局对象来联系这些cookie操作。对象名可以理解为命名空间。对cookie操作经常以下操作。
(1)设置cookie包括了添加和修改功能,事实上如果原有cookie名称已经存在,那么添加此cookie就相当于修改了此cookie。在设置 cookie的时候可能还会有一些可选项,用于指定cookie的生命周期、访问路径以及访问域。为了让cookie中能够存储中文,该方法中还需要对存储的值进行编码。
(2)删除一个cookie,删除cookie只需将一个cookie的过期时间设置为过去的一个时间即可,它接收一个cookie的名称为参数,从而删除此cookie。
(3)取一个cookie的值,该方法接收cookie名称为参数,返回该cookie的值。因为在存储该值的时候已经进行了编码,所以取值时应该能自动解码,然后返回。2.代码(思路):
1. 创建Cookie对象
因为是作为类名或者命名空间的作用,所以和Math对象类似,这里使用Cookie来表示该对象:
var Cookie=new Object();
2. 实现设置Cookie的方法
方法为:setCookie(name,value,option);其中name是要设置cookie的名称;value是设置cookie的值;option包括了其他选项,是一个对象作为参数。其实现如下:
Cookie.setCookie=function(name,value,option){
//用于存储赋值给document.cookie的cookie格式字符串
var str=name+"="+escape(value);
if(option){
//如果设置了过期时间
if(option.expireDays){
var date=new Date();
var ms=option.expireDays*24*3600*1000;
date.setTime(date.getTime()+ms);
str+="; expires="+date.toGMTString();
}
if(option.path)str+="; path="+path; //设置访问路径
if(option.domain)str+="; domain"+domain; //设置访问主机
if(option.secure)str+="; true"; //设置安全性
}
document.cookie=str;
}
3. 实现取Cookie值的方法
方法为:getCookie(name);其中name是指定cookie的名称,从而根据名称返回相应的值。实现如下:
Cookie.getCookie=function(name){
var cookieArray=document.cookie.split("; "); //得到分割的cookie名值对
var cookie=new Object();
for(var i=0;i<cookieArray.length;i++){
var arr=cookieArray[i].split("="); //将名和值分开
if(arr[0]==name)return unescape(arr[1]); //如果是指定的cookie,则返回它的值
}
return "";
}

4. 实现删除Cookie的方法
方法为:deleteCookie(name);其中name是指定cookie的名称,从而根据这个名称删除相应的cookie。在实现中,删除cookie是通过调用setCookie来完成的,将option的expireDays属性指定为负数即可:
Cookie.deleteCookie=function(name){
this.setCookie(name,"",{expireDays:-1}); //将过期时间设置为过去来删除一个cookie
}
通过下面的代码,整个Cookie对象创建完毕后,可以将其放到一个大括号中来定义,例如:
var Cookie={
setCookie:function(){},
getCookie:function(){},
deleteCookie:function(){}
}
通过这种形式,可以让Cookie的功能更加清晰,它作为一个全局对象,大大方便了对Cookie的操作,例如:
Cookie.setCookie("user","jack");
alert(Cookie.getCookie("user"));
Cookie.deleteCookie("user");
alert(Cookie.getCookie("user"));
上面的代码就先建立了一个名为user的cookie,然后删除了该cookie。两次alert输出语句显示了执行的效果。
本节通过建立一个Cookie对象来处理cookie,方便了操作,也体现了面向对象的编程思想:把相关的功能封装在一个对象中。考虑到 JavaScript语言的特点,本章没有选择需要创建类的面向对象编程的例子,那和一般面向对象语言没有大的不同。而是以JavaScript中可以直接创建对象为特点介绍了Cookie对象的实现及其工作原理。事实上这也和JavaScript内部对象Math的工作原理是类似的。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
<script type="text/javascript" src="js/Cookie.js"></script>

</head>
<body>
<button onclick="Cookie.setCookie('username','json');alert('set cookie successed!');">设置Cookie值</button>
<button onclick="alert(Cookie.getCookie('username'))">获取Cookie值</button>
<button onclick="Cookie.deleteCookie('username');alert('deleted!')">删除Cookie</button>
</body>
</html>

 js代码:

/**
* Created by shizhiwei on 2016/9/12.
*/
//创建全局的实例
var Cookie={
setCookie:function(){},
getCookie:function(){},
deleteCookie:function(){}
}

//cookie的名称,值,选项 setCookie起到修改和添加的作用
Cookie.setCookie=function(name,value,option){
//用于存储赋值给document.cookie的cookie格式字符串
var str=name+"="+escape(value);
if(option){
//如果设置了过期时间
if(option.expireDays){
var date=new Date();
var ms=option.expireDays*24*3600*1000;
date.setTime(date.getTime()+ms);
str+="; expires="+date.toGMTString();
}
if(option.path)str+="; path="+path; //设置访问路径
if(option.domain)str+="; domain="+domain; //设置访问主机
if(option.secure)str+="; true"; //设置安全性
}
document.cookie=str;
}

//取值
Cookie.getCookie=function(name){
var cookieArray=document.cookie.split("; "); //得到分割的cookie名值对
var cookie=new Object();
for(var i=0;i<cookieArray.length;i++){
var arr=cookieArray[i].split("="); //将名和值分开
if(arr[0]==name)return unescape(arr[1]); //如果是指定的cookie,则返回它的值
}
return "";
}

Cookie.deleteCookie=function(name){
this.setCookie(name,"",{expireDays:-1}); //将过期时间设置为过去来删除一个cookie
}

 

 

js的压缩和混淆技术:

一:

JavaScript Compressor

网址:​​http://dean.edwards.name/packer/​​ 优点:简单易用

缺点:只能在线,不够安全容易出错

 

二:

JSA(javascript Analyser)--JSA 是一个脚本压缩、混淆、分析工具, 也是 ​​JSI​​ 的编译工具, 有着非常可观的压缩质量和压缩比率。 JSA 的运用,可以减轻网络负担,保护源代码。

官网下载地址:

​http://sourceforge.net/project/showfiles.php?group_id=175776​​  

在线压缩:http://www.xidea.org/project/jsa/

 

JSA的特点:

        相比之下JSA的是当前比较安全最有效的压缩工具。

JSA 不仅提供代码压缩功能,还可以做格式化,脚本分析。

脚本分析功能可以用于查看脚本信息,以及查找脚本中的潜在问题。

比如查看脚本中申明了那些函数,变量。

使用了那些外部变量。等等。。。

JSA的压缩过程分两步,第一步是语法压缩,安全且有效。

第二步是文本压缩,目前采用的是

JavaScript Compressor的压缩算法。

(http://dean.edwards.name/packer/ )

这些都可以在设置窗口设置。

默认情况先用语法压缩,当文件大于1000k且采用文本压缩仍然可以压缩到原来大小90%时才在原来基础上采用文本压缩。

详见:​​Google Closure Compiler​​​​压缩优化规则初探​

 

开启服务端的HTTP压缩功能(IIS)

 开启服务端的HTTP压缩功能(IIS)

 

 详见:​​IIS​​​​上启用​​​​Gzip​​​​压缩​​​​(HTTP​​​​压缩​​​​) ​​​​详解​​​​.​​​​pdf​

 

JavaScript的调试(Firebug Lite)

下载地址:​​http://getfirebug.com/firebuglite#Install​

 

实战: Firebug Lite (IE下如何使用FireBugLite)

1、在线调用

2、引用网上路径

<script type="text/javascript" src="https://getfirebug.com/firebug-lite.js"></script>

3、引用本地路径

​http://getfirebug.com/firebuglite#Stable​



标签:function,obj,onShow,Javascript,cookie,事件,var,设计模式
From: https://blog.51cto.com/u_10999550/5776548

相关文章