看案例前可以先看看基础篇: JavaScript 面向对象(一) —— 基础篇
案例——面向对象的选项卡:把面向过程的程序一步步改成面向对象的形式,使其能够更加的通用(但是通用的东西,一般会比较臃肿)。
下面是一个简单的选项卡,也是我们常见的面向过程的创建形式。
1 <!DOCTYPE html>
2 <html 3 head 4 style 5 #tabBox input {
6 background: #F6F3F3;
7 border 1px solid #FF0000 8 }
9 #tabBox .active 10 #E9D4D411 12 #tabBox div 13 width300px;
14 height250px15 displaynone16 padding 10px17 18 19 20 </21 Meta charset="utf-8" />
22 title>选项卡23 script24 window.onload=function(){
25 var tabBox document.getElementById('tabBox);
26 tabBtn tabBox.getElementsByTagName(input27 tabDiv div28
29 for( i0;i<tabBtn.length;i++){
30 tabBtn[i].index i;
31 tabBtn[i].onclick = (){
32 j;jtabBtn.length;j33 tabBtn[j].className'';
34 tabDiv[j].style.display35 }
36 this.classNameactive37 tabDiv[.index].style.displayblock38 };
39 }
40 };
41 42 43
44 body45 div id="tabBox"46 input type="button" value="游戏" class="active" 47 ="旅行" 48 ="音乐" 49 ="display:block;">GTA5、孤岛惊魂div50 >澳大利亚、西藏51 >暗里着迷、一生有你52 53 54 >
效果:
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面来一步步改成面向对象的形式。
1.首先将嵌套的函数拿到window.onload外面,不能有函数嵌套,可以有全局变量。如下:所有的改写最终效果都不变。
24 //将在嵌套函数里的变量提取到全局中
25 null26 27
28 window.onload tabBtn tabDiv 32
33 35 此处调用函数即可
36 clickBtn;
39
40 将嵌套函数提取到全局中
41 clickBtn(){
42 43 tabBtn[j].className44 tabDiv[j].style.display45 46 47 tabDiv[48 49
50 51 52
54 55 56 57 58 59 60 61 62 63 >
2.将全局的变量变为对象的属性,全局的函数变为对象的方法;将window.onload里的代码提取到一个构造函数里面,在window.onload里创建对象即可;(下面的代码执行起来是有问题的)。
这里必须注意:在构造函数Tab里的this跟之前this所代表的是不同的(此处是通过new来创建对象的);在上面的示例中,this指的是调用者;在构造函数里,this指向的是var tab = new Tab() ,即tab这个对象,注意是对象。
说一下这段代码的问题:我们在Tab的原型上添加clickBtn方法后,clickBtn方法里的this本应该是指向var tab = new Tab()的,但是我们在第44行将clickBtn添加给了this.tabBtn[i],即input按钮,clickBtn的所属由Tab对象变成了input按钮(第49行)。
clickBtn的所属变成input按钮后,那么clickBtn里的this指向按钮,那再来看clickBtn里的代码,this.tabBtn、this.tabDiv,input按钮里有这两个属性吗?没有,所以会出错!
24
25 tab new Tab("27 }
28
29 /**
* 将之前window.onload里的代码提到一个构造函数里
* [可以将这个Tab构造函数想象成一个Tab类]
32 * @param {Object} id:选项卡id以参数的形式传入
33 */
34 Tab(id){
35 document.getElementById(id);
36 将之前的全局变量变为对象的属性
37 .tabBtn 38 .tabDiv 39
40 .tabBtn.length;i41 .tabBtn[i].index 42
43 此处这种方式调用函数,已经将clickBtn的所属变成this.tabBtn[i]
44 .tabBtn[i].onclick .clickBtn;
46 47 将之前的全局函数添加到构造函数的原型里,作为对象的一个方法
Tab.prototype.clickBtn 49 alert(this); HTMLInputElement
50 .tabBtn.length;j51 .tabBtn[j].className52 .tabDiv[j].style.display53 54 55 .tabDiv[56 57
58 59 60
61 62 63 64 65 66 67 68 69 70 71 >
将clickBtn赋给input按钮后,方法内的this也指向了input按钮:执行第49行代码的效果
3.将clickBtn的调用放在一个函数里,这样就不会改变clickBtn的所属了。
看第41-47行,注意在function里需要用到外部保存的变量_this。再看第52行,此时弹出的是一个Object,说明clickBtn的所属关系没变,还是Tab对象。
但是还有另一个问题,此时clickBtn里的this指向对象,那么看第57、58行中this.className、this.index,此处的this指的是tab对象,那么对象中有这两个属性吗?没有,还会出错!
* 选项卡
* @param {Object} id:选项卡id
32 33 34 35
38
39 40 将this保存成一个变量,就可以在下面代码中调用对象的方法了
42 _this 此处这种方式调用函数,就不会改变clickBtn方法的所属关系
45 注意此处不能直接使用this,this指向this.tabBtn[i]
_this.clickBtn();
49 50 点击选项卡按钮
51 52 ); Object
53 54 55 57 58 59 60
63
64 65 69 70 71 72 73 74 >
4. 以参数的形式将点击的按钮传入clickBtn中,看第44行代码,以及54,55行代码
43 注意参数this代表的是this.tabBtn[i],即input按钮
_this.clickBtn(48 将点击的按钮以参数的形式传入
(btn){
54 btn.className.tabDiv[btn.index].style.display>
5.最终版 —— 将代码提取到一个单独的js文件中,在用的时候引入即可。一般花大时间去写一个面向对象的程序,就是为了能够复用,以及方便的使用。
tab.js
/* * 选项卡
* @param {Object} id 选项卡id
4 5 function 6 var tabBox = 7 this.tabBtn = tabBox.getElementsByTagName('input' 8 this.tabDiv = tabBox.getElementsByTagName('div' 9
10 for(var i=0;i<this.tabBtn.length;i++11 this.tabBtn[i].index =12 var _this = this13 this.tabBtn[i].onclick = 14 _this.clickBtn(15 16 }
17 };
18 19 * 为Tab原型添加点击选项卡方法
20 * @param {Object} btn 点击的按钮
21 22 Tab.prototype.clickBtn = var j=0;j<this.tabBtn.length;j++24 this.tabBtn[j].className=''25 this.tabDiv[j].style.display='none'26 27 btn.className='active'28 this.tabDiv[btn.index].style.display='block'29 };
使用:tab.html 可以看到使用的时候,就可以很简单的创建两个选项卡出来了。
.tab input .tab .active .tab div <!-- 引入tab.js -->
24 script ="text/javascript" src="../js/tab.js" ></25 26
28 tab1 tabBox129
30 tab2 tabBox232
33 34 35
36 37 class="tab" id="tabBox1"38 39 40 41 42 43 44 br 46 ="tabBox2"="技术"="工具" ="网站" >Java、Spring>Eclipse、HBuilder52 >博客园、CSD53 55
看的有点晕吧,一定要好好理解JS面向对象中的this。js中面向对象大部分时候出问题就是出在this的处理上,需要注意。
面向过程:简洁、美观、容易维护;
面向对象:容易出错、混乱、难以维护;面向对象相对面向过程来说,写代码的时候麻烦些,但是用起来很方便,面向过程则相反。
开发面向对象的程序需要有一个好的面向对象的思维,即将具体对象抽象成一个构造函数的过程。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
再来简单总结一下JS面向对象中的this,this一般会在两种情况下出问题,一是使用定时器、二是事件,从上面的例子中也可以看出来。注意下面的说法是在构造函数里哦,其它情况下,this指向的是调用者。
可以看到效果没有将姓名显示出来,其实看到这里原因应该很清楚了,就是第14行代码中this.name,此处的this指向谁?指向window,因为setInterval是属于window的。
3 ="UTF-8" 5 6
7 Person(name){
8 .name name;
9 定时器
setInterval(.showName,300011 Person.prototype.showName alert(window
姓名:+.name);
16
17 p1 Person(jiangzhou18
19 21 >
效果:


解决办法:上面例子中已经列出来了,就是用一个function将要执行的代码包起来,使其所属关系不会发生变化,注意function里调用方法时使用的是外部变量'_this'。事件的处理在上面的例子中已经说明了。
9
10 11
_this.showName();
},1)">//[Object Object]
.name); 姓名:jianghzou
19 20
21 22
23 25 >
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
再附上一个案例 —— 拖拽
原始的面向过程代码:
4 ="UTF-8" #Box width 100px 8 height background blue position absolute11 >拖拽14 15 oBox16 disX disY window.onload20 oBoxdocument.getElementById(Box21
22 oBox.onmousedownfnDown;
23 };
24 鼠标按下事件
fnDown(ev){
26 oEvent ev||event;
disX oEvent.clientX - oBox.offsetLeft;
disY oEvent.clientY oBox.offsetTop;
29
document.onmousemove fnMove;
document.onmouseup fnUp;
鼠标移动事件
fnMove(ev){
oEventev36
oBox.style.left disX + px oBox.style.top disY 鼠标抬起事件
41 fnUp(){
42 45 47
48 49 ="Box"50 >
下面是面向对象的代码
drag.js
* 拖拽
* @param {Object} id div的id
Drag(id){
this.oBox =this.disX = 0this.disY = 011
12 this.oBox.onmousedown = 13 _this.fnDown();
14 }
//鼠标按下
17 Drag.prototype.fnDown = (ev){
18 var oEvent = ev || event;
19
this.disX = oEvent.clientX - .oBox.offsetLeft;
this.disY = oEvent.clientY - .oBox.offsetTop;
22
24
25 document.onmousemove = _this.fnMove();
27 };
28 document.onmouseup = 29 _this.fnUp();
30 31 32 鼠标移动
33 Drag.prototype.fnMove = 34 var oEvent= ev ||35
36 this.oBox.style.left = oEvent.clientX - this.disX + 'px'this.oBox.style.top = oEvent.clientY - this.disY + 'px'38 39 鼠标抬起
40 Drag.prototype.fnUp = 41 document.onmousemove = null42 document.onmouseup = 43 }
drag.html