本人自学前端近半年,js达到熟练的水平,面向对象思想、this指向有一定的了解,但是要用面向对象思想写代码就一脸懵逼了,最近看到某课堂的视频(里面广告嫌疑,就不说是啥了),觉得讲的很好,因此想和大家分享一下,希望那些和我一样有一定基础但是不知道怎么写的小伙伴也能愉快的写代码。
我们以选项卡的实现为例,先给出html的结构和样式:
<style type="text/css">
#div1 div{
width: 200px;
height:200px;
border: 1px #000 solid;
display: none;
}
.active{
background: red;
}
</style>
<body>
<div id="div1">
<button class="active">1</button>
<button>2</button>
<button>3</button>
<div style="display: block;">111</div>
<div>222</div>
<div>333</div>
</div>
</body>
我们先用过程式的编程思想来实现,然后将其改为面向对象思想的代码。
window.onload=function(){
//获取元素
var oParent=document.getElementById('div1');
var btns=oParent.getElementsByTagName('button');
var divs=oParent.getElementsByTagName('div');
//通过循环给每个btn添加点击事件
for (var i = 0; i < btns.length; i++) {
btns[i].index=i;//存储当前btn的下标
btns[i].onclick=function(){
for (var i = 0; i < btns.length; i++) {
btns[i].className='';
divs[i].style.display='none';
}
this.className='active';
divs[this.index].style.display='block';//让对应当前btn的div显示
}
}
}
对于小白,也就是和我一样的人,一般就是写出上面的代码。现在我们要用面向对象的思想来改写,首先我们要对以上代码进行变形,使其不要出现函数的嵌套(如onload函数中就存在嵌套函数),变量可以改为全局变量,所以讲以上代码做出如下改变:变量变为全局变量,分出来一个init()函数和change()函数。
var oParent,btns,divs;
window.onload=function(){
oParent=document.getElementById('div1');
btns=oParent.getElementsByTagName('button');
divs=oParent.getElementsByTagName('div');
init();
};
function init(){
for (var i = 0; i < btns.length; i++) {
btns[i].index=i;
btns[i].onclick=change;
}
}
function change(){
for (var i = 0; i < btns.length; i++) {
btns[i].className='';
divs[i].style.display='none';
}
this.className='active';
divs[this.index].style.display='block';
}
根据以上代码的变形,我们现在用面向对象思想来编写代码,创建构造函数,添加属性及方法。
window.onload=function(){
var t1=new Tab();
t1.init();
};
function Tab(){
oParent=document.getElementById('div1');
btns=oParent.getElementsByTagName('button');
divs=oParent.getElementsByTagName('div');
}
Tab.prototype.init=function(){
for (var i = 0; i < this.btns.length; i++) {
btns[i].index=i;
btns[i].onclick=change;
}
}
Tab.prototype.change=function() {
for (var i = 0; i < this.btns.length; i++) {
btns[i].className='';
divs[i].style.display='none';
}
className='active';
divs[btn.index].style.display='block';
};
将结构写出来,复制改过的代码,此时面向对象的思想已经初现端倪了。最后一步就是添加this了,因此将每个属性前面都添加this。
window.onload=function(){
var t1=new Tab();
t1.init();
};
function Tab(){
this.oParent=document.getElementById('div1');
this.btns=this.oParent.getElementsByTagName('button');
this.divs=this.oParent.getElementsByTagName('div');
}
Tab.prototype.init=function(){
for (var i = 0; i < this.btns.length; i++) {
this.btns[i].index=i;
this.btns[i].onclick=change();
}
}
Tab.prototype.change=function() {
for (var i = 0; i < this.btns.length; i++) {
this.btns[i].className='';
this.divs[i].style.display='none';
}
this.className='active';
this.divs[this.index].style.display='block';
};
以上代码就完成了吗?答案是否定的。为什么?还是因为this指向的问题。让我们一个一个来看。首先构造函数中的this,由于是用new关键字,因此this指向t1,没问题。init()方法,由于调用方式是t1.init(),this指向也为t1,没问题。那问题肯定是在change()方法中了,首先看看其调用形式this.btns[i].onclick=change();其this指向为this.btns[i],即当前点击的按钮,因此在change()内部,this.btns[i],this.divs[i]都不存在,因为btns和divs是t1的属性,其他的this如this.className指向是正确的,因此我们要改变this指向,一般都是将this指向改为指向对象,即t1。怎么改this指向?this指向与函数的调用方式有关,因此作出如下改变。
Tab.prototype.init=function(){
var This=this;
for (var i = 0; i < this.btns.length; i++) {
this.btns[i].index=i;
this.btns[i].onclick=function(){
This.change(this);
}
}
}
Tab.prototype.change=function(btn) {
for (var i = 0; i < this.btns.length; i++) {
this.btns[i].className='';
this.divs[i].style.display='none';
}
btn.className='active';
this.divs[btn.index].style.display='block';
};
首先在init()中,将this存在变量This中,用匿名函数中采用This.change(this);方式来调用方法。同时将this(指向当前点击的btn)以参数形式传入change()中,这样一个面向对象思想的代码就写出来了。
不知道大家看了会不会对大家有所帮助,现在我用面向过程思想写了一个拖拽的代码,大家可以试着将其改为面向对象的代码,代码如下,过程中会有几个坑,一个就是this指向的问题,另外一个就是事件函数的问题(ev只能出现在事件函数中)。最后跟大家分享一个小经验,事件和定时器很容易造成this指向的问题,因此在面向对象编程过程中要特别注意。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>drag</title>
<style type="text/css">
#div1{
width: 100px;
height: 100px;
background: red;
position: absolute;
}
</style>
<script type="text/javascript">
window.onload=function(){
var oDiv=document.getElementById('div1');
var disX=0;
var disY=0;
oDiv.onmousedown=function(ev){
var ev=ev || window.event;
disX=ev.clientX-oDiv.offsetLeft;
disY=ev.clientY-oDiv.offsetTop;
document.onmousemove=function(ev){
var ev=ev || window.event;
oDiv.style.left=ev.clientX-disX+'px';
oDiv.style.top=ev.clientY-disY+'px';
};
document.onmouseup=function(){
document.onmousemove=null;
document.onmouseup=null;
}
return false;
}
}
</script>
</head>
<body>
<div id='div1'></div>
</body>
</html>