• JavaScript 面向对象(二) —— 案例篇


    看案例前可以先看看基础篇: 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             background: #E9D4D4;
    11         }
    12         #tabBox div {
    13             width:300px; 
    14             height:250px; 
    15             display:none;
    16             padding: 10px;
    17             background: #E9D4D4;
    18             border: 1px solid #FF0000;
    19         }
    20     </style>
    21     <meta charset="utf-8" />
    22     <title>选项卡</title>
    23     <script>
    24         window.onload=function(){
    25             var tabBox = document.getElementById('tabBox');
    26             var tabBtn = tabBox.getElementsByTagName('input');
    27             var tabDiv = tabBox.getElementsByTagName('div');
    28             
    29             for(var i=0;i<tabBtn.length;i++){
    30                 tabBtn[i].index = i;
    31                 tabBtn[i].onclick = function (){
    32                     for(var j=0;j<tabBtn.length;j++){
    33                         tabBtn[j].className='';
    34                         tabDiv[j].style.display='none';
    35                     }
    36                     this.className='active';
    37                     tabDiv[this.index].style.display='block';
    38                 };
    39             }
    40         };
    41     </script>
    42 </head>
    43 
    44 <body>
    45     <div id="tabBox">
    46         <input type="button" value="游戏" class="active" />
    47         <input type="button" value="旅行" />
    48         <input type="button" value="音乐" />
    49         <div style="display:block;">GTA5、孤岛惊魂</div>
    50         <div>澳大利亚、西藏</div>
    51         <div>暗里着迷、一生有你</div>
    52     </div>
    53 </body>
    54 </html>

    效果:

     -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

     下面来一步步改成面向对象的形式。

     1.首先将嵌套的函数拿到window.onload外面,不能有函数嵌套,可以有全局变量。如下:所有的改写最终效果都不变。

     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             background: #E9D4D4;
    11         }
    12         #tabBox div {
    13             width:300px; 
    14             height:250px; 
    15             display:none;
    16             padding: 10px;
    17             background: #E9D4D4;
    18             border: 1px solid #FF0000;
    19         }
    20     </style>
    21     <meta charset="utf-8" />
    22     <title>选项卡</title>
    23     <script>
    24         //将在嵌套函数里的变量提取到全局中
    25         var tabBtn = null;
    26         var tabDiv = null;
    27         
    28         window.onload = function(){
    29             var tabBox = document.getElementById('tabBox');
    30             tabBtn = tabBox.getElementsByTagName('input');
    31             tabDiv = tabBox.getElementsByTagName('div');
    32             
    33             for(var i=0;i<tabBtn.length;i++){
    34                 tabBtn[i].index = i;
    35                 //此处调用函数即可
    36                 tabBtn[i].onclick = clickBtn;
    37             }
    38         };
    39         
    40         //将嵌套函数提取到全局中
    41         function clickBtn(){
    42             for(var j=0;j<tabBtn.length;j++){
    43                 tabBtn[j].className='';
    44                 tabDiv[j].style.display='none';
    45             }
    46             this.className='active';
    47             tabDiv[this.index].style.display='block';
    48         };
    49         
    50     </script>
    51 </head>
    52 
    53 <body>
    54     <div id="tabBox">
    55         <input type="button" value="游戏" class="active" />
    56         <input type="button" value="旅行" />
    57         <input type="button" value="音乐" />
    58         <div style="display:block;">GTA5、孤岛惊魂</div>
    59         <div>澳大利亚、西藏</div>
    60         <div>暗里着迷、一生有你</div>
    61     </div>
    62 </body>
    63 </html>

    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按钮里有这两个属性吗?没有,所以会出错!

     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             background: #E9D4D4;
    11         }
    12         #tabBox div {
    13             width:300px; 
    14             height:250px; 
    15             display:none;
    16             padding: 10px;
    17             background: #E9D4D4;
    18             border: 1px solid #FF0000;
    19         }
    20     </style>
    21     <meta charset="utf-8" />
    22     <title>选项卡</title>
    23     <script>
    24         
    25         window.onload = function(){
    26             var tab = new Tab("tabBox");
    27         }
    28     
    29         /**
    30          * 将之前window.onload里的代码提到一个构造函数里
    31          * [可以将这个Tab构造函数想象成一个Tab类]
    32          * @param {Object} id:选项卡id以参数的形式传入
    33          */
    34         function Tab(id){
    35             var tabBox = document.getElementById(id);
    36             //将之前的全局变量变为对象的属性
    37             this.tabBtn = tabBox.getElementsByTagName('input');
    38             this.tabDiv = tabBox.getElementsByTagName('div');
    39             
    40             for(var i=0;i<this.tabBtn.length;i++){
    41                 this.tabBtn[i].index = i;
    42                 
    43                 //此处这种方式调用函数,已经将clickBtn的所属变成this.tabBtn[i]
    44                 this.tabBtn[i].onclick = this.clickBtn;
    45             }
    46         };
    47         //将之前的全局函数添加到构造函数的原型里,作为对象的一个方法
    48         Tab.prototype.clickBtn = function(){
    49             alert(this); //HTMLInputElement
    50             for(var j=0;j<this.tabBtn.length;j++){
    51                 this.tabBtn[j].className='';
    52                 this.tabDiv[j].style.display='none';
    53             }
    54             this.className='active';
    55             this.tabDiv[this.index].style.display='block';
    56         };
    57         
    58     </script>
    59 </head>
    60 
    61 <body>
    62     <div id="tabBox">
    63         <input type="button" value="游戏" class="active" />
    64         <input type="button" value="旅行" />
    65         <input type="button" value="音乐" />
    66         <div style="display:block;">GTA5、孤岛惊魂</div>
    67         <div>澳大利亚、西藏</div>
    68         <div>暗里着迷、一生有你</div>
    69     </div>
    70 </body>
    71 </html>

    将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对象,那么对象中有这两个属性吗?没有,还会出错!

     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             background: #E9D4D4;
    11         }
    12         #tabBox div {
    13             width:300px; 
    14             height:250px; 
    15             display:none;
    16             padding: 10px;
    17             background: #E9D4D4;
    18             border: 1px solid #FF0000;
    19         }
    20     </style>
    21     <meta charset="utf-8" />
    22     <title>选项卡</title>
    23     <script>
    24         
    25         window.onload = function(){
    26             var tab = new Tab("tabBox");
    27         }
    28     
    29         /**
    30          * 选项卡
    31          * @param {Object} id:选项卡id
    32          */
    33         function Tab(id){
    34             var tabBox = document.getElementById(id);
    35             
    36             this.tabBtn = tabBox.getElementsByTagName('input');
    37             this.tabDiv = tabBox.getElementsByTagName('div');
    38             
    39             for(var i=0;i<this.tabBtn.length;i++){
    40                 this.tabBtn[i].index = i;
    41                 //将this保存成一个变量,就可以在下面代码中调用对象的方法了
    42                 var _this = this;
    43                 //此处这种方式调用函数,就不会改变clickBtn方法的所属关系
    44                 this.tabBtn[i].onclick = function(){
    45                     //注意此处不能直接使用this,this指向this.tabBtn[i]
    46                     _this.clickBtn();
    47                 };
    48             }
    49         };
    50         //点击选项卡按钮
    51         Tab.prototype.clickBtn = function(){
    52             alert(this); //Object
    53             for(var j=0;j<this.tabBtn.length;j++){
    54                 this.tabBtn[j].className='';
    55                 this.tabDiv[j].style.display='none';
    56             }
    57             this.className='active';
    58             this.tabDiv[this.index].style.display='block';
    59         };
    60         
    61     </script>
    62 </head>
    63 
    64 <body>
    65     <div id="tabBox">
    66         <input type="button" value="游戏" class="active" />
    67         <input type="button" value="旅行" />
    68         <input type="button" value="音乐" />
    69         <div style="display:block;">GTA5、孤岛惊魂</div>
    70         <div>澳大利亚、西藏</div>
    71         <div>暗里着迷、一生有你</div>
    72     </div>
    73 </body>
    74 </html>

    4. 以参数的形式将点击的按钮传入clickBtn中,看第44行代码,以及54,55行代码

     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             background: #E9D4D4;
    11         }
    12         #tabBox div {
    13             width:300px; 
    14             height:250px; 
    15             display:none;
    16             padding: 10px;
    17             background: #E9D4D4;
    18             border: 1px solid #FF0000;
    19         }
    20     </style>
    21     <meta charset="utf-8" />
    22     <title>选项卡</title>
    23     <script>
    24         
    25         window.onload = function(){
    26             var tab = new Tab("tabBox");
    27         }
    28     
    29         /**
    30          * 选项卡
    31          * @param {Object} id:选项卡id
    32          */
    33         function Tab(id){
    34             var tabBox = document.getElementById(id);
    35             
    36             this.tabBtn = tabBox.getElementsByTagName('input');
    37             this.tabDiv = tabBox.getElementsByTagName('div');
    38             
    39             for(var i=0;i<this.tabBtn.length;i++){
    40                 this.tabBtn[i].index = i;
    41                 var _this = this;
    42                 this.tabBtn[i].onclick = function(){
    43                     //注意参数this代表的是this.tabBtn[i],即input按钮
    44                     _this.clickBtn(this);
    45                 };
    46             }
    47         };
    48         //将点击的按钮以参数的形式传入
    49         Tab.prototype.clickBtn = function(btn){
    50             for(var j=0;j<this.tabBtn.length;j++){
    51                 this.tabBtn[j].className='';
    52                 this.tabDiv[j].style.display='none';
    53             }
    54             btn.className='active';
    55             this.tabDiv[btn.index].style.display='block';
    56         };
    57         
    58     </script>
    59 </head>
    60 
    61 <body>
    62     <div id="tabBox">
    63         <input type="button" value="游戏" class="active" />
    64         <input type="button" value="旅行" />
    65         <input type="button" value="音乐" />
    66         <div style="display:block;">GTA5、孤岛惊魂</div>
    67         <div>澳大利亚、西藏</div>
    68         <div>暗里着迷、一生有你</div>
    69     </div>
    70 </body>
    71 </html>

    5.最终版 —— 将代码提取到一个单独的js文件中,在用的时候引入即可。一般花大时间去写一个面向对象的程序,就是为了能够复用,以及方便的使用。

    tab.js

     1 /**
     2  * 选项卡
     3  * @param {Object} id 选项卡id
     4  */
     5 function Tab(id){
     6     var tabBox = document.getElementById(id);
     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 = i;
    12         var _this = this;
    13         this.tabBtn[i].onclick = function(){
    14             _this.clickBtn(this);
    15         };
    16     }
    17 };
    18 /**
    19  * 为Tab原型添加点击选项卡方法
    20  * @param {Object} btn 点击的按钮
    21  */
    22 Tab.prototype.clickBtn = function(btn){
    23     for(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 可以看到使用的时候,就可以很简单的创建两个选项卡出来了。

     1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4     <style>
     5         .tab input {
     6             background: #F6F3F3;
     7             border: 1px solid #FF0000;
     8         }
     9         .tab .active {
    10             background: #E9D4D4;
    11         }
    12         .tab div {
    13             width:300px; 
    14             height:250px; 
    15             display:none;
    16             padding: 10px;
    17             background: #E9D4D4;
    18             border: 1px solid #FF0000;
    19         }
    20     </style>
    21     <meta charset="utf-8" />
    22     <title>选项卡</title>
    23     <!-- 引入tab.js -->
    24     <script type="text/javascript" src="../js/tab.js" ></script>
    25     <script>
    26         
    27         window.onload = function(){
    28             var tab1 = new Tab("tabBox1");
    29             
    30             var tab2 = new Tab("tabBox2");
    31         }
    32     
    33     </script>
    34 </head>
    35 
    36 <body>
    37     <div class="tab" id="tabBox1">
    38         <input type="button" value="游戏" class="active" />
    39         <input type="button" value="旅行" />
    40         <input type="button" value="音乐" />
    41         <div style="display:block;">GTA5、孤岛惊魂</div>
    42         <div>澳大利亚、西藏</div>
    43         <div>暗里着迷、一生有你</div>
    44     </div>
    45     <br />
    46     <div class="tab" id="tabBox2">
    47         <input type="button" value="技术" class="active" />
    48         <input type="button" value="工具" />
    49         <input type="button" value="网站" />
    50         <div style="display:block;">Java、Spring</div>
    51         <div>Eclipse、HBuilder</div>
    52         <div>博客园、CSD</div>
    53     </div>
    54 </body>
    55 </html>

    效果:

     

    看的有点晕吧,一定要好好理解JS面向对象中的this。js中面向对象大部分时候出问题就是出在this的处理上,需要注意。

    面向过程:简洁、美观、容易维护;

    面向对象:容易出错、混乱、难以维护;面向对象相对面向过程来说,写代码的时候麻烦些,但是用起来很方便,面向过程则相反。

    开发面向对象的程序需要有一个好的面向对象的思维,即将具体对象抽象成一个构造函数的过程。

     

     -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    再来简单总结一下JS面向对象中的this,this一般会在两种情况下出问题,一是使用定时器、二是事件,从上面的例子中也可以看出来。注意下面的说法是在构造函数里哦,其它情况下,this指向的是调用者。

    可以看到效果没有将姓名显示出来,其实看到这里原因应该很清楚了,就是第14行代码中this.name,此处的this指向谁?指向window,因为setInterval是属于window的。

     1 <!DOCTYPE html>
     2 <html>
     3     <meta charset="UTF-8" />
     4     <head>
     5         <script>
     6             
     7             function Person(name){
     8                 this.name = name;
     9                 //定时器
    10                 setInterval(this.showName, 3000);
    11             }
    12             Person.prototype.showName = function(){
    13                 alert(this); //window
    14                 alert("姓名:"+this.name);
    15             }
    16             
    17             var p1 = new Person("jiangzhou");
    18             
    19         </script>
    20     </head>
    21 </html>

    效果:

     解决办法:上面例子中已经列出来了,就是用一个function将要执行的代码包起来,使其所属关系不会发生变化,注意function里调用方法时使用的是外部变量'_this'。事件的处理在上面的例子中已经说明了。

     1 <!DOCTYPE html>
     2 <html>
     3     <meta charset="UTF-8" />
     4     <head>
     5         <script>
     6             
     7             function Person(name){
     8                 this.name = name;
     9                 
    10                 var _this = this;
    11                 
    12                 setInterval(function(){
    13                     _this.showName();
    14                 }, 3000);
    15             }
    16             Person.prototype.showName = function(){
    17                 alert(this); //[Object Object]
    18                 alert("姓名:"+this.name); //姓名:jianghzou
    19             }
    20             
    21             var p1 = new Person("jiangzhou");
    22             
    23         </script>
    24     </head>
    25 </html>

     

      -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

     再附上一个案例 —— 拖拽

    原始的面向过程代码:

     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset="UTF-8">
     5         <style>
     6             #box {
     7                 width: 100px; 
     8                 height: 100px; 
     9                 background: blue; 
    10                 position: absolute;
    11             }
    12         </style>
    13         <title>拖拽</title>
    14         <script>
    15             var oBox=null;
    16             var disX=0;
    17             var disY=0;
    18             
    19             window.onload=function(){
    20                 oBox=document.getElementById('box');
    21                 
    22                 oBox.onmousedown=fnDown;
    23             };
    24             //鼠标按下事件
    25             function fnDown(ev){
    26                 var oEvent = ev||event;
    27                 disX = oEvent.clientX - oBox.offsetLeft;
    28                 disY = oEvent.clientY - oBox.offsetTop;
    29                 
    30                 document.onmousemove = fnMove;
    31                 document.onmouseup = fnUp;
    32             }
    33             //鼠标移动事件
    34             function fnMove(ev){
    35                 var oEvent=ev||event;
    36                 
    37                 oBox.style.left = oEvent.clientX - disX + 'px';
    38                 oBox.style.top = oEvent.clientY - disY + 'px';
    39             }
    40             //鼠标抬起事件
    41             function fnUp(){
    42                 document.onmousemove = null;
    43                 document.onmouseup = null;
    44             }
    45         </script>
    46     </head>
    47 
    48 <body>
    49     <div id="box"></div>
    50 </body>
    51 </html>

    下面是面向对象的代码

    drag.js

     1 /**
     2  * 拖拽
     3  * @param {Object} id div的id
     4  */
     5 function Drag(id){
     6     this.oBox = document.getElementById(id);
     7     this.disX = 0;
     8     this.disY = 0;
     9     
    10     var _this = this;
    11     
    12     this.oBox.onmousedown = function(){
    13         _this.fnDown();
    14     }
    15 }
    16 //鼠标按下
    17 Drag.prototype.fnDown = function(ev){
    18     var oEvent = ev || event;
    19     
    20     this.disX = oEvent.clientX - this.oBox.offsetLeft;
    21     this.disY = oEvent.clientY - this.oBox.offsetTop;
    22     
    23     var _this = this;
    24     
    25     document.onmousemove = function(){
    26         _this.fnMove();
    27     };
    28     document.onmouseup = function(){
    29         _this.fnUp();
    30     };
    31 }
    32 //鼠标移动
    33 Drag.prototype.fnMove = function(ev){
    34     var oEvent= ev || event;
    35     
    36     this.oBox.style.left = oEvent.clientX - this.disX + 'px';
    37     this.oBox.style.top = oEvent.clientY - this.disY + 'px';
    38 }
    39 //鼠标抬起
    40 Drag.prototype.fnUp = function(){
    41     document.onmousemove = null;
    42     document.onmouseup = null;
    43 }

    drag.html 

     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset="UTF-8">
     5         <style>
     6             div {
     7                 position: absolute;
     8             }
     9         </style>
    10         <title>拖拽</title>
    11         <script type="text/javascript" src="../js/drag.js" ></script>
    12         <script>
    13             window.onload = function(){
    14                 var drag1 = new Drag("box1");
    15                 
    16                 var drag1 = new Drag("box2");
    17             };
    18         </script>
    19     </head>
    20 
    21 <body>
    22     <div id="box1" style="background: red; 200px;height: 200px;"></div>
    23     
    24     <div id="box2" style="background: blue; 100px;height: 300px;"></div>
    25 </body>
    26 </html>

    效果:

     

    JavaScript 面向对象(三) —— 高级篇

  • 相关阅读:
    python常见错误
    接口自动化常用断言方法python
    Mysql2docx自动生成数据库说明文档
    常用的实用小工具
    移动App专项测试
    AndroidStudio 快捷键(最实用的20个)(转)
    Linux常用命令大全(非常全!!!)(转)
    Fiddler使用教程(转)
    Subversion Edge
    杂点
  • 原文地址:https://www.cnblogs.com/chiangchou/p/js-oop2.html
Copyright © 2020-2023  润新知