JavaScript 面向對象(三) —— 高級篇


JavaScript 面向對象(一) —— 基礎篇

JavaScript 面向對象(二) —— 案例篇

 

一、json方式的面向對象

首先要知道,js中出現的東西都能夠放到json中。關於json數據格式這里推薦一篇博客:JSON 數據格式

先看下json創建的簡單對象:相比基礎篇中的構造函數、原型等的創建方式,json方式簡單方便;但是缺點很明顯,如果想創建多個對象,那么會產生大量重復代碼,不可取。

JSON方式適用於只創建一個對象的情況,代碼簡介又優雅。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="UTF-8">
 5         <title></title>
 6         <script>
 7             var person = {  8  name: "jiangzhou",  9  age: 22, 10  showName: function(){ 11  alert(this); //[Object Object]
12  alert("姓名:"+this.name); 13  }, 14  showAge: function(){ 15  alert("年齡:"+this.age); 16  } 17  }; 18  person.showName(); 19  person.showAge(); 20             
21         </script>
22     </head>
23 </html>

JSON在JS面向對象的應用中,主要的一個作用就是命名空間:如果有大量常用的js函數,利用json,我們可以將同一類函數放在一個“類”里,類似於java那樣,這樣我們就能很好的管理和查找使用這些js函數,看下面的例子就很好理解了。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="UTF-8">
 5         <title></title>
 6         <script>
 7             //仿java.lang包
 8             var lang = {};  9             
10             /** 11  * 仿java.lang.Math類 12              */
13  lang.Math = { 14                 /** 15  * 求絕對值 16  * @param {Object} a 17                  */
18  abs: function(a){ 19                     return a > 0 ? a : -a; 20  }, 21                 /** 22  * 求最大值 23  * @param {Object} a 24  * @param {Object} b 25                  */
26  max: function(a, b){ 27                     return a > b ? a : b; 28  }, 29                 /** 30  * PI 31                  */
32  PI: 3.1415926
33  } 34             
35             /** 36  * 仿java.lang.String類 37              */
38  lang.String = { 39                 /** 40  * 求字符串長度 41  * @param {Object} str 42                  */
43  length: function(str){ 44                     return str.length; 45  }, 46                 /** 47  * 將字符串轉為小寫 48  * @param {Object} str 49                  */
50  toLowerCase: function(str){ 51                     return str.toLowerCase(); 52  }, 53                 /** 54  * 將字符串轉為大寫 55  * @param {Object} str 56                  */
57  toUpperCase: function(str){ 58                     return str.toUpperCase(); 59  } 60  } 61             
62             //調用
63  alert(lang.Math.abs(-19)); //19
64  alert(lang.Math.PI); 65  alert(lang.String.toUpperCase("abcdefg")); //ABCDEFG
66             
67         </script>
68     </head>
69 </html>

 

二、面向對象的繼承

先舉個簡單的例子來說一下JS中的繼承,Student <extends> Person;

在js中,通過call來調用父類的構造方法繼承父類的屬性(第33行),通過原型來繼承父類的方法(第39行)。注意:先調用父類構造函數,再添加自己的屬性;先繼承父類的方法,再添加自己的方法。

這里解釋下為什么調用Person.call(this, name, sex)就相當於是在調用父類的構造方法:先問一下這個call中的this是誰?這里指向對象student吧。

所以,在子構造函數中調用Person.call()時,那么構造函數Person里的兩行代碼this.name=name, this.sex=sex中this就是代表student了,所以這兩行代碼相當於是在為student添加name和sex屬性。

但是,下面的通過原型來繼承父類的方法,即Student.prototype = Person.prototype,是有問題的,這種方式將影響父類(繼承是不能影響父類的),此時Person的原型中有了個showMajor方法(第50行),為什么呢?先思考下,下面解釋。

 1 <!DOCTYPE html>
 2 <html>
 3     <meta charset="UTF-8" />
 4     <head>
 5         <script>
 6             
 7             /**  8  * Person 父類 人  9  * @param {Object} name 姓名 10  * @param {Object} sex 性別 11              */
12             function Person(name, sex){ 13                 this.name = name; 14                 this.sex = sex; 15  } 16  Person.prototype.showName = function(){ 17  alert("姓名:"+this.name); 18  } 19  Person.prototype.showSex = function(){ 20  alert("性別:"+this.sex); 21  } 22             
23         /*-----------------------------------------------------*/
24             
25             /** 26  * Student 學生 繼承 人 27  * @param {Object} name 28  * @param {Object} sex 29  * @param {Object} major 學生特有屬性:專業 30              */
31             function Student(name, sex, major){ 32                 //調用父類的構造函數
33  Person.call(this, name, sex); 34                 
35                 //添加自己的屬性
36                 this.major = major; 37  } 38             //繼承父類原型中的方法
39  Student.prototype = Person.prototype; 40             //添加自己特有的方法
41  Student.prototype.showMajor = function(){ 42  alert("專業:"+this.major); 43  } 44             
45             var student = new Student("bojiangzhou", "", "信息管理"); 46  student.showName(); 47  student.showSex(); 48  student.showMajor(); 49             
50  alert(Person.prototype.showMajor); 51         </script>
52     </head>
53 </html>

第50行彈出的信息:

為了解釋為什么通過Student.prototype = Person.prototype來繼承父類的方法會影響父類,下面舉一個數組的例子,一看就知道怎么回事了。

為什么arr1和arr2彈出來的一樣呢?第15、16行顯示arr1和arr2是一個對象。對象!應該很清楚了吧,arr1和arr2都是指向這個數組對象的一個引用,所以改變arr2時,arr1也變了。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="UTF-8">
 5     </head>
 6     <script>
 7         var arr1 = [1,2,3,4,5];  8         var arr2 = arr1;  9         
10  arr2.push(6); 11         
12  alert(arr1); //彈出1,2,3,4,5,6
13  alert(arr2); //彈出1,2,3,4,5,6
14         
15  alert(typeof arr1); //object
16  alert(typeof arr2); //object
17     </script>
18 </html>

其實我們主要是想獲得arr1數組的一個副本,怎么做才能不改變arr1呢,看下面:

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="UTF-8">
 5     </head>
 6     <script>
 7         var arr1 = [1,2,3,4,5];  8         var arr2 = [];  9         
10         //復制arr1的數據即可
11         for(var i=0;i<arr1.length;i++){ 12  arr2[i]=arr1[i]; 13  } 14         
15  arr2.push(6); 16         
17  alert(arr1); //彈出1,2,3,4,5
18  alert(arr2); //彈出1,2,3,4,5,6
19         
20     </script>
21 </html>

同樣的,我們也可以通過這種方式為繼承的子類添加父類原型中的方法,而又不影響父類(38-41行):

 1 <!DOCTYPE html>
 2 <html>
 3     <meta charset="UTF-8" />
 4     <head>
 5         <script>
 6             
 7             /**  8  * Person 父類 人  9  * @param {Object} name 姓名 10  * @param {Object} sex 性別 11              */
12             function Person(name, sex){ 13                 this.name = name; 14                 this.sex = sex; 15  } 16  Person.prototype.showName = function(){ 17  alert("姓名:"+this.name); 18  } 19  Person.prototype.showSex = function(){ 20  alert("性別:"+this.sex); 21  } 22             
23         /*-----------------------------------------------------*/
24             
25             /** 26  * Student 學生 繼承 人 27  * @param {Object} name 28  * @param {Object} sex 29  * @param {Object} major 學生特有屬性:專業 30              */
31             function Student(name, sex, major){ 32                 //調用父類的構造函數
33  Person.call(this, name, sex); 34                 
35                 //添加自己的屬性
36                 this.major = major; 37  } 38             //繼承父類原型中的方法
39             for(var p in Person.prototype){ 40  Student.prototype[p] = Person.prototype[p]; 41  } 42             
43             //添加自己特有的方法
44  Student.prototype.showMajor = function(){ 45  alert("專業:"+this.major); 46  } 47             
48             var student = new Student("bojiangzhou", "", "信息管理"); 49  student.showName(); 50  student.showSex(); 51  student.showMajor(); 52             
53  alert(Person.prototype.showMajor); 54         </script>
55     </head>
56 </html>

第53行彈出信息:Person中沒有showMajor方法了。

 

最后,以案例篇中最后給出的拖拽例子來應用下繼承,那個拖拽有一個問題,就是沒有控制拖拽出邊界的問題。

先貼出之前的拖拽版本:

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;width: 200px;height: 200px;"></div>
23     
24     <div id="box2" style="background: blue;width: 100px;height: 300px;"></div>
25 </body>
26 </html>

效果:可以看到紅色和藍色的都出邊界了,但我們又不想去修改代碼,那我們怎么做?學過java的應該都知道可以寫一個子類來做一些更加具體的操作,又保留了父類的功能,就是繼承。

DragLimit.js:DragLimit繼承自Drag,控制了不能出邊界

 1 /**  2  * 限制邊界的拖拽,繼承自Drag  3  * @param {Object} id  4  */
 5 function DragLimit(id){  6     Drag.call(this, id);  7 }  8 //繼承方法
 9 for(var p in Drag.prototype){ 10     DragLimit.prototype[p] = Drag.prototype[p]; 11 } 12 /** 13  * 覆寫父類的鼠標移動方法,控制不能移出邊界 14  */
15 DragLimit.prototype.fnMove = function(ev){ 16     var oEvent= ev || event; 17     
18     var left = oEvent.clientX - this.disX; 19     var top = oEvent.clientY - this.disY; 20     
21     //控制邊界
22     if(left < 0){ 23         left = 0; 24     } else if(left > document.documentElement.clientWidth-this.oBox.offsetWidth){ 25         left = document.documentElement.clientWidth-this.oBox.offsetWidth; 26  } 27     if(top <= 0){ 28         top = 0; 29     } else if(top > document.documentElement.clientHeight-this.oBox.offsetHeight){ 30         top = document.documentElement.clientHeight-this.oBox.offsetHeight; 31  } 32     
33     this.oBox.style.left = left + 'px'; 34     this.oBox.style.top = top + 'px'; 35 }

dragLimit.html

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

效果:藍色是不能移出邊界的。

 

 三、JS中的對象

js中的對象分為本地對象、內置對象、宿主對象,這里給出W3School文檔供參考:ECMAScript 對象類型

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM