日期:2014-05-16  浏览次数:20317 次

Javascript静态类数组与框架基本实现
先来讲讲静态类数组(类数组):
       JavaScript是一个弱类型的语言,但是我们可以通过不同的方式来侧面的实现类的创建,不管是工厂函数、函数原型还是静态类,均可实现模拟类,每一种都有它的特点。
       静态类数组即是建立在静态类的基础上实现的数组模型。
       var class = {
              name : "object",
              color : "red"
          }
以上是创建了一个静态类class,我们知道,调用类的成员有两种方式
点号形式:class.name
索引形式:class["name"]
其中索引形式与数组的形式非常相像,我们不妨设计一个如下样式的静态类:
        var LikeArray = {
                0 : "A",
                1 : "B",
                2 : "C"    
          } 
如果现在我用索引的形式来调用类的成员属性0,1,2,即LikeArray[0]、LikeArray[1],这样便与数组对象十分相似,唯一的区别就是没有length属性(我们可以通过添加length成员来模拟length属性)。
注:只有静态类的成员名才能以纯数字来命名,调用成员若为纯数字命名则可以省略双引号。

我们先把上面讲的放一放,来看一个别的函数——apply:
apply是一个特殊又十分有用的东西,它的作用是可以改变当前作用对象的方法内this指针指向另一个对象。
语法为:[对象.]方法.apply(另一个对象[,参数数组]);
如:
var one = function(){
        this.arr = ["a","b","c"];
        this.show = function(){
          alert(this.arr);
        }
      }
var two = function(){
        this.arr = ["d","e","f"]; 
      }
     var obj = new one();
     obj.show.apply(new two());  //使用one对象的show方法但其内部this却指向了two对象,因此会弹出d,e,f
以上也可以说明,apply使two对象继承了one对象的成员属性或方法并立即使用。

下面,我们结合静态类和apply动态生成静态类数组:

var obj = {
   length : 0      //①
}
var arr  = ["a","b","c","d","e"];  //定义数组并初始化
[].push.apply(obj,arr);   // ②
alert(obj[1]);  //Debug,弹出b

①这里仿照数组,模拟设置了一个length属性(必须,后面介绍)
② []表示数组对象,等同于new Array(),通过apply使obj类继承Array类的push方法并使用,同时给push方法传入参数arr。整体效果即为,将数组arr强行压入obj类,使它成为类似于如下的形式:
var obj = {
   length : 0,
   0 : "a",
   1:  "b",
   2:  "c",
……
}
注:由于push方法有一个关联属性——length,push每一个数组元素,length都会自动加一,因此length不可缺少,我们为静态类obj特意加上length属性,这样[].push.apply(obj,arr);才能正常运行。

这样,整个静态类数组(类数组)简单的实现就完成了,用处不是很多,基本是用在Javascript框架(库)中去,其中jQuery库也牵扯到此内容。下面,我们就制作一个简单Js框架(类似于Jquery),功能虽简单,只要大家勤动手动脑,为这个小小的框架扩展,就可以完成一个属于自己的js库。

/* Your JavaScript Framework */
var fw = $ = window.$ = window.fw  = function(selector){
            return new fw.fn.init(selector);    //fw对象以静态类数组形式存在,生成的实际是init的实例
   }
fw.fn = {  //新的命名空间名fw.fn
     setArray : function(arr){  //生成fw对象的类数组
       this.length = 0;  // 模拟length属性初始化
       [].push.apply( this, arr ); // 继承数组对象push方法
  },
     init : function(selector){
         var d=[];   //定义一个临时的DOM数组,用来存储DOM对象
         if(selector.indexOf("#")== 0){    //获取一个ID元素
         d[0]=document.getElementById(selector.substr(1)); // 唯一性的ID元素赋予d[0]即可
          }
         else if(selector.indexOf(".")== 0){    //获取指定Class元素集合
         var j=0;
          var A = document.getElementsByTagName('*'); // 以下均为获取class算法
                  for (var i=0; i< A.length; i++ ) { 
                     if (A.className == selector.substr(1) ) {
                         d[j++] = A; 
                    } 
                  } 
        } 
          else{   //获取标签元素集合
           d=document.getElementsByTagName(selector);  // 标签是一个集合,因此可以直接赋予临时数组d保存
          }
   var arr = []; // 定义空数组
   for(var i=0; i<d .length; i++){  //遍历临时数组d
     arr.push(d);  //将d中的DOM元素依次压入数组arr中
   }
    d = null;  //释放临时DOM数组
    return this.setArray(arr);  // 返回类数组对象
  },
html : function(value){
     if(typeof(value)=="undefined"){  //如果参数为空,则说明是读取内容
            return this[0].innerHTML;   // this[0]的目的是将fw对象转换成DOM对象,以便使用innerHTML方法
     }
     else{
            this[0].innerHTML=value; //关于对象转换将在以后的文章中介绍,如果这篇原理了解了相信大家会自己明白
     }
      return this;  //返回fw对象,可以实现连写
  }
}
fw.fn.init.prototype = fw.fn;   // 将fw.fn内的所有成员复制给init,这样new出来的init对象才能使用自己框架的方法

现在我们开始调试:
<div id="a">Hello </div>
<p class="b"> My </p>
<span> Framework<span>

<script language="javascript">
var s = $("#a").html() + $(".b").html() + $("span").html(); // fw框架选择器,调用我们的html方法
alert(s);
$("#a").html("Welcome ");  // 有参数的html方法可以修改内容
</script>

?