使用JS闭包特性的简单应用

 最近在做一个项目,由于对JS的一些特性不是很熟悉,走了些弯路,不过到最后总算解决了问题。现在把项目中一些经验心得发出来,希望能对以后解决问题的人有些帮助。  

简单描述下项目需求:网络中有一台主机(Web站点),需要对分布到各地的节点发送命令,检测命令执行结果,同时进行状态检测。由于各地节点是同构的,所以希望在进行命令执行和状态检测时,能够起多个线程,每个线程对应一个节点,将结果即时反应到页面。        

最开始的设想是这样的:把所有的节点放到数组,页面开始执行时遍历数组,将节点作为参数传递到实际中的函数,函数使用setInterval来启动,以此来模拟多线程。

代码如下:见index1.html    

<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
< HTML >
 
< HEAD >
  
< TITLE >  实例1  </ TITLE >
  
< META  NAME ="Generator"  CONTENT ="EditPlus" >
  
< META  NAME ="Author"  CONTENT ="" >
  
< META  NAME ="Keywords"  CONTENT ="" >
  
< META  NAME ="Description"  CONTENT ="" >
 
</ HEAD >
 
< BODY >
    
< SCRIPT  LANGUAGE ="JavaScript" >
    
<!--
        
        
function  Node(id,name,cn){
            
this .id  =  id;
            
this .name  =  name;
            
this .cn  =  cn;
        }
        
var  nodes  =   new  Array();
        nodes[
0 =   new  Node( 1 , " node1 " , " 节点1 " );
        nodes[
1 =   new  Node( 2 , " node2 " , " 节点2 " );

        
var  nodeConfig  =  {};
        nodeConfig.ticks 
=   4   *   1000 // 刷新频率
        nodeConfig.msg  =   " 运行中 " ;

        
function  showStatus(node){
            alert(node.name 
+   " : "    +  nodeConfig.msg);
        }            

        
function  start(){
            
var  len  =  nodes.length;
            
for  ( var  i  = 0 ; i  <  len ; i ++ ){
                setInterval(
function (){showStatus(nodes[i])} ,nodeConfig.ticks);
            }
        }
        start();            
    
// -->
     </ SCRIPT >
 
</ BODY >
</ HTML >

正当我信心满满的想查看结果时,发现出错。查找了一些资料,大概明白是由于setInterval执行时,传进来的形参已经脱离了其定义的函数环境,已经被垃圾回收器回收了。由于时间紧迫,来不及细查资料,暂时采取了一种其他的方法来实现:每个节点对应一个函数。

 代码如下:见index2.html       

<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
< HTML >
 
< HEAD >
  
< TITLE >  实例2  </ TITLE >
  
< META  NAME ="Generator"  CONTENT ="EditPlus" >
  
< META  NAME ="Author"  CONTENT ="" >
  
< META  NAME ="Keywords"  CONTENT ="" >
  
< META  NAME ="Description"  CONTENT ="" >
 
</ HEAD >
 
< BODY >
    
< SCRIPT  LANGUAGE ="JavaScript" >
    
<!--
        
function  Node(id,name,cn){
            
this .id  =  id;
            
this .name  =  name;
            
this .cn  =  cn;
        }
        
var  nodes  =   new  Array();
        nodes[
0 =   new  Node( 1 , " node1 " , " 节点1 " );
        nodes[
1 =   new  Node( 2 , " node2 " , " 节点2 " );

        
var  nodeConfig  =  {};
        nodeConfig.ticks 
=   4   *   1000 // 刷新频率
        nodeConfig.msg  =   " 运行中 " ;

        
function  showStatus1(node){
            alert(node.name 
+   " : "    +  nodeConfig.msg);
        }        
        
        
function  showStatus2(node){
            alert(node.name 
+   " : "    +  nodeConfig.msg);
        }

        
function  start(){            
            setInterval(
function (){showStatus1(nodes[ 0 ])} ,nodeConfig.ticks);
            setInterval(
function (){showStatus2(nodes[ 1 ])} ,nodeConfig.ticks);
        }

        start();    
    
// -->
     </ SCRIPT >
 
</ BODY >
</ HTML >

         此段代码能够执行,但是其缺陷显而易见:每当增加一个节点时,就要手动的去改代码,增加函数。而这些代码大部分都是相同的,虽然可以直接Copy,维护难度却会一直增加,一不小心就不知道是哪个节点更改错了。

稍微闲下来时,继续查找资料,终于找了闭包的概念。关于闭包的介绍,此处只是简单概述,具体的可以看下面的参考资料,那里面介绍的很详细。

所谓“闭包”,就是在构造函数体内定义另外的函数作为目标对象的方法函数,而这个对象的方法函数反过来引用外层函数体中的临时变量。这使得只要目标对象在生存期内始终能保持其方法,就能间接保持原构造函数体当时用到的临时变量值。(引自参考文章)

我自己的理解就是:外部变量保存了某个内部函数的指针,由于JS垃圾回收机制,也间接的保存了内部函数定义环境的一些变量。

呵呵,知道这个方法后,就对原来的代码改写一遍。为了更OO一点,又对程序重构了一番。

代码如下:见index3.html

<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
< HTML >
 
< HEAD >
  
< TITLE >  实例4  </ TITLE >
  
< META  NAME ="Generator"  CONTENT ="EditPlus" >
  
< META  NAME ="Author"  CONTENT ="" >
  
< META  NAME ="Keywords"  CONTENT ="" >
  
< META  NAME ="Description"  CONTENT ="" >
 
</ HEAD >

 
< BODY >
    
< SCRIPT  LANGUAGE ="JavaScript" >
    
<!--

        
var  nodeConfig  =  {};
        nodeConfig.ticks 
=   4   *   1000 // 刷新频率
        nodeConfig.msg  =   " 运行中 " ;

        
function  Node(id,name,cn){
            
this .id  =  id;
            
this .name  =  name;
            
this .cn  =  cn;
        }        

        
// 节点数组可从服务器端生成
         var  nodes  =   new  Array();
        nodes[
0 =   new  Node( 1 , " node1 " , " 节点1 " );
        nodes[
1 =   new  Node( 2 , " node2 " , " 节点2 " );            

        
var  NodeManager  =   function (newObj){
            
var  pro = this ;
            
for ( var  i  in  newObj){    // 将配置转变为自身属性
                pro[i]  =  newObj[i];
            }            
        };
        
        NodeManager.prototype 
=  {
            showStaus:
function (node){
                alert(node.name 
+   " : "   +   this .msg);
            },
            start:
function (){
                
var  len  =  nodes.length,    ins  =   this ;     // 将实例赋值给变量,以便在此方法中能够使用
                 for ( var  i  =   0 ; i  <  len; i ++ ){
                    
var  f  =   function (idx){                                                  
                        setInterval(
function (){ ins.showStaus(nodes[idx])},ins.ticks);                                
                    }
                    f(i);
                }
            }
        }        

        
var  m  =   new  NodeManager({
            ticks:nodeConfig.ticks,
            msg:nodeConfig.msg            
        });

        m.start();
    
// -->
     </ SCRIPT >
 
</ BODY >
</ HTML >

 至此,才终于将程序划上稍显完美的句号。

 

参考文章: 

深入理解JavaScript闭包(closure)
http://www.felixwoo.com/archives/247 

一个js闭包的小例子
http://blog.pchome.net/article/182960.html 

js对象属性类型

http://orn827.blog.163.com/blog/static/1113902032009681365891/

 
源码下载:/Files/hellofox2000/js_thread.rar

你可能感兴趣的:(js闭包)