先来讲讲静态类数组(类数组):
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>