一、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 對象類型