duansky'weblog

统计

留言簿(1)

阅读排行榜

评论排行榜

【Prototype 1.4.0】源码解读----全文注释版

/*   Prototype JavaScript framework, version 1.4.0
 *  (c) 2005 Sam Stephenson <sam@conio.net>
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://prototype.conio.net/
 
 *  这是一个JavaScript的框架,致力于简化动态的Web开发,完全按照面对对象的思想
 *  进行Javascript开发,添加了迭代器的概念增强Javascript的设计能力。
 *  Prototype框架构思独特充满了技巧性的代码,方便易用的工具类!
 *
/*--------------------------------------------------------------------------
*/

 
  
/*  【Prototype】定义一个全局对象,提供一个全局的基本信息和工具  */
var  Prototype  =   {
  Version: '
1.4 . 0 ',  // 可以作为版本检测用
//
用于脚本检测的正则表达式,经常使用所以放在这里起到全局常量的作用
  ScriptFragment: '( ? : < script. *?> )((\n | \r | .) *? )( ? : < \ / script > )',

  emptyFunction: 
function ()  {} , // 空函数
  K:  function (x)  { return  x} // K方法返回参数本身,在后面经常用到
}


/* ======================================================================================== */

/*
 *【Class】对象的作用只有一个就是提供了一个定义类的模式
 * 仅含有create 一个方法,返回一个构造函数。 
 * 一般使用如下  
 *     var X = Class.create();  返回一个类型  
 * 要使用 X 类型,需继续用 new X()来获取一个实例 这与C# JAVA类似
 * 返回的构造函数会执行名为 initialize 的方法, initialize 是 Ruby 对象的构造器方法名字。 
 * 此时initialize方法还没有定义,其后的代码中创建新类型时会建立相应的同名方法,可以看作是一个抽象方法。 
 * 从C#角度讲可以理解为用Class.create()创建一个继承Object基类的类。 
 * 
 
*/
 

var  Class  =   {
  create: 
function ()  {
    
return   function ()  {   // 下面使用Apply方法传递参数是一个常用的技巧
       this .initialize.apply( this , arguments);
    }

  }

}


/* ======================================================================================== */


// Abstract是一个空对象,它的作用仅仅是作为一个抽象的命名空间,所有在该对象下定义的类都是抽象类
//
从而从形式上与实体类分开
var  Abstract  =   new  Object();

/*
 *Object是所有对象的基类,这个基类有两个静态方法
 
*/
 
// 把Source的所有属性和方法传递给Destination,实现了继承的效果
Object.extend  =   function (destination, source)  {
  
for  (property  in  source)  {
    destination[property] 
=  source[property];
  }

  
return  destination;
}

// 观察Object的组成,需要参数中的object实现自己的inspect方法
Object.inspect  =   function (object)  {
  
try   {
    
if  (object  ==  undefined)  return  'undefined';
    
if  (object  ==   null return  ' null ';
    
return  object.inspect  ?  object.inspect() : object.toString();
  }
  catch  (e)  {
    
if  (e  instanceof  RangeError)  return  '';
    
throw  e;
  }

}


/* ======================================================================================== */


// 【Function】是所有函数对象的基类,可以通过对它的扩展实现对所有函数对象添加功能
/*  这里在绑定的时候旧可以传递参数而不是调用的时候才指定参数,bind方法接收多个参数
  将函数绑定到第一个参数指定的对象上,并返回该方法的调用句柄
*/

Function.prototype.bind 
=   function ()  {
  
//  $A()方法的作用是把参数专为数组 
   // 数组的shift方法作用是删除数组的第一个元素
   var  __method  =   this , args  =  $A(arguments), object  =  args.shift();
  
return   function ()  {
    
return  __method.apply(object, args.concat($A(arguments)));
    
// 这里的$A(arguments)是条用返回函数句柄时传递的参数,不是bind方法的参数
  }

}

/*
 * 和bind一样,不过这个方法一般用做html控件对象的事件处理。所以要传递event对象 
 * 好像是重载了_method方法
 
*/
 

Function.prototype.bindAsEventListener 
=   function (object)  {
  
var  __method  =   this ;
  
return   function (event)  {
    
return  __method.call(object, event  ||  window.event);
  }

}


/* ======================================================================================== */

// 【Function】是所有数值类型的基类

Object.extend(Number.prototype, 
{
  toColorPart: 
function ()  {            // RGB-》16进制颜色
     var  digits  =   this .toString( 16 );
    
if  ( this   <   16 return  ' 0 +  digits;
    
return  digits;
  }
,

  succ: 
function ()  // 数值加一 var a=1; var b=a.succ; 那么b=2
     return   this   +   1 ;
  }
,

  times: 
function (iterator) 
  
// 这里的参数iterator是一个迭代器作用就是循环调用指定次数的iterator函数
   // $R(start,end,exclusive)是创建ObjectRnge对象的快捷方式
    $R( 0 this true ).each(iterator);
    
return   this ;
  }

}
);

/* ======================================================================================== */

// 提供了一个方法these,要求参数是函数的句柄,可以有多个。作用就是返回第一个成功执行的函数的返回值
var  Try  =   {
  these: 
function ()  {
    
var  returnValue;

    
for  ( var  i  =   0 ; i  <  arguments.length; i ++ {
      
var  lambda  =  arguments[i];
      
try   {
        returnValue 
=  lambda();
        
break ;
      }
  catch  (e)  {}
    }


    
return  returnValue;
  }

}


/* ======================================================================================== */

// 定时器类用来实现Window.setInterval的效果,在给定时间间隔执行某一个函数,增加了对重复执行的控制S
var  PeriodicalExecuter  =  Class.create();
PeriodicalExecuter.prototype 
=   {
  initialize: 
function (callback, frequency)  {
  
// 构造函数指定回调函数和执行频率,单位是秒
     this .callback  =  callback;
    
this .frequency  =  frequency;
    
this .currentlyExecuting  =   false ;

    
this .registerCallback();
  }
,
  
/*  开始调用定时器,无需显示调用,在构造函数中就实现了自动调用,这一下面的
this.onTimerEvent.bind(this)如果写成this.onTimerEvent则this指针就会指向widows对象即setInterval的默认对象
从而不能正确的引用到下面两个函数上,也就失去了对正在执行函数的控制
*/


  registerCallback: 
function ()  {
    setInterval(
this .onTimerEvent.bind( this ),  this .frequency  *   1000 );
  }
,
// 下面的函数相当于是回调函数的一个代理, setInterval是到了指定的时间就会强制执行而这里
//
加入了一个判断如果callback函数执行的时间超过了一个时间片,则阻止其被重复执行
  onTimerEvent:  function ()  {
    
if  ( ! this .currentlyExecuting)  {
      
try   {
        
this .currentlyExecuting  =   true ;
        
this .callback();
      }
  finally   {
        
this .currentlyExecuting  =   false ;
      }

    }

  }

}

/* 使用举例:
function GetOnlineCount()
{//获得在线人数
}
new PeriodicalExecuter(GetOnlineCount,10)每10秒获取一次
*/


/* ======================================================================================== */
/*  框架核心内容--------【基础工具类】
/*========================================================================================
*/


 
/* document.getElementById(id)获取一个指定ID的结点,是这个方法的快捷方式和扩展
 可以指定多个参数返回一个对象数组。参数也不一定是ID也可以是对象本身的引用,例如
 $('id')等价于$($('id'))
  
*/

function  $()  {
  
var  elements  =   new  Array();

  
for  ( var  i  =   0 ; i  <  arguments.length; i ++ {
    
var  element  =  arguments[i];
    
if  ( typeof  element  ==  'string')
      element 
=  document.getElementById(element);

    
if  (arguments.length  ==   1 )
      
return  element;

    elements.push(element);
  }


  
return  elements;
}


/* ======================================================================================== */
// 【String】类的扩展

// 删除字符串中的HTML标记
Object.extend(String.prototype,  {
  stripTags: 
function ()  {
    
return   this .replace( /< \ /? [ ^> ] +>/ gi, '');
  }
,
// 删除字符串中的脚本块
  stripScripts:  function ()  {
    
return   this .replace( new  RegExp(Prototype.ScriptFragment, 'img'), '');
  }
,
// 提取字符串中的所有脚本块,作为数组返回,每一个脚本作为一个数组元素
  extractScripts:  function ()  {
    
var  matchAll  =   new  RegExp(Prototype.ScriptFragment, 'img');
    
var  matchOne  =   new  RegExp(Prototype.ScriptFragment, 'im');
    
return  ( this .match(matchAll)  ||  []).map( function (scriptTag)  {
      
return  (scriptTag.match(matchOne)  ||  ['', ''])[ 1 ];
    }
);
  }
,
// 提取字符串中的脚本并执行
  evalScripts:  function ()  {
    
return   this .extractScripts().map(eval);
  }
,
// 将字符串进行html编码例如"<" --》"&lt"
  escapeHTML:  function ()  {
    
var  div  =  document.createElement('div');
    
var  text  =  document.createTextNode( this );
    div.append