框架设计

思路:

  1. 选择引擎

  2. DOM操作模块(增删)

  3. 事件模块click,on,…

  4. 属性模块attr,text,html,val…

  5. 样式模块css,hasClass…

  6. 动画模块

  7. 整合


做个小例子:

页面有一堆div和p,给它们加上背景色

1
2
3
4
5
6
7
8
var aDiv = document.getElementsByTagName("div");
var aP = document.getElementsByTagName("p");
for(var i = 0;i<aDiv.length;i++){
aDiv[i].style.backgroundColor = "red";
}
for(var i = 0;i<aP.length;i++){
aP[i].style.backgroundColor = "red";
}

这么做有什么不好的地方?

  1. 代码冗余
  2. 无法复用
  3. 容错
  4. 效率
  5. 性能

函数化

所以我们考虑给它函数化

1
2
3
4
5
6
7
8
9
10
11
12
var g = function(tag){
return document.getElementsByTagName(tag);
};
var aDiv = g("div");
var aP = g("p");
var each = function(arr){
for(var i=0;i<arr.length;i++){
arr[i].style.backgroundColor = "red";
}
};
each(aDiv);
each(aP);

显然each这个函数写的太死

我们思考一下:如果你想要遍历一个数组,要对数组做什么事情?

凡是涉及到遍历才可以完成的事情都应该可以做(修改,查询)

1
2
3
var arr = [1,2,3,4,5];
要求:
1.求和 2.求最大值 3.求最小值 4.查找3 5.查找5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
var sum = 0;
for(var i=0;i<arr.length;i++){
sum += arr[i];
}
console.log(sum);
var max = arr[0];
for(var i=0;i<arr.length;i++){
if(arr[i]>max){
max = arr[i];
}
}
console.log(max);
var min = arr[0];
for(var i=0;i<arr.length;i++){
if(arr[i]<min){
min = arr[i];
}
}
console.log(min);
var find1 = -1;
for(var i=0;i<arr.length;i++){
if(arr[i] == 3){
find1 = i;
break;
}
}
var find2 = -1;
for(var i=0;i<arr.length;i++){
if(arr[i] == 5){
find2 = i;
break;
}
}

发现

我们可以发现,遍历操作有一个特点:所有都需要循环,就是循化体不同。

那么我们来优化一下each

1
2
3
4
5
6
function each(arr,string){
for(var i=0;i<arr.length;i++){
//执行string
}
}
怎么执行string呢?eval(),或者我们传个函数进去
1
2
3
4
5
function each(arr,fn){
for(var i=0;i<arr.length;i++){
fn(); //注意:这里函数要传参数啊,要不然怎么能读到arr[i]呢?
}
}
1
2
3
4
5
function each(arr,fn){
for(var i=0;i<arr.length;i++){
fn(arr[i]);
}
} //第一次优化

我们来求个和试试

1
2
3
4
var sum = 0;
each(arr,function(v){
sum += v;
})

再来求个最大值试试

1
2
3
4
5
6
var max = arr[0];
each(arr,function(v){
if(v>max){
max = v;
}
});

是不是完美了呢?不,如果我们求下标为偶数的和呢?没办法了吧,所以我们还需要把下标i传进去。

1
2
3
4
5
function each(arr,fn){
for(var i=0;i<arr.length;i++){
fn(i,arr[i]);
}
} //第二次优化
1
2
3
4
5
6
7
var arr = [1,2,3,4,5];
var sum = 0;
each(arr, function (i, v) {
if (i % 2) return; //如果下标是奇数,就跳过
sum += v;
});
console.log(sum); //9

完美了吗?不,如果要查找怎么办呢?没有break,那么会循环整个数组,性能低,并且,如果有相同的,后面的会把前面的覆盖掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
function each(arr,fn){
for(var i=0;i<arr.length;i++){
if( fn(i,arr[i]) === false) break; //第三次优化
}
}
var index = -1;
each(arr,function(i,v){
if(v == 3){
index = i;
return false;
}
});
console.log(index);

我们还不满足

1
2
3
4
5
6
7
8
function each(arr,fn){
for(var i=0;i<arr.length;i++){
if( fn(i,arr[i]) === false) break; //第三次优化
}
}
each(arr,function(i,v){
console.log(this); //window,我们的期望是this指向arr[i]
})

可以这么做

1
2
3
4
5
6
7
8
function each(arr,fn){
for(var i=0;i<arr.length;i++){
if( fn.call(arr[i],i,arr[i]) === false) break; //第四次优化
}
}
each(arr,function(i,v){
console.log(this); //Number {[[PrimitiveValue]]: 1}...(打印四次)
})

好了,我们再来写前面的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function getByTag (tag){
return document.getElementsByTagName(tag);
}
function each(arr,fn){
for(var i=0;i<arr.length;i++){
if( fn.call(arr[i],i,arr[i]) === false) break;
}
}
var aDiv = getByTag("div");
var aP = getByTag("p");
each(aDiv,function(){
this.style.backgroundColor = "red";
});
each(aP,function(){
this.style.backgroundColor = "red";
})

本文结束,感谢阅读。

本文作者:melody0z
本文链接:https://melodyvoid/JavaScript/framework-design.html
欢迎转载,转载请注明文本链接

坚持原创技术分享,您的支持将鼓励我继续创作!