1. 程式人生 > >JavaScript 面向物件(一)——基礎篇

JavaScript 面向物件(一)——基礎篇

學好JS的面向物件,能很大程度上提高程式碼的重用率,像jQuery,easyui等,這篇部落格主要從細節上一步步講JS中如何有效地建立物件,也可以看到常見的建立物件的方式,最後也會附上一些JS面向物件的案例。

一、面向物件(Java面向物件亦是如此)

1.物件:物件是一個整體,對外提供一些操作。

2.面向物件:使用物件時,只關注物件提供的功能,不關注其內部細節。比如電腦——有滑鼠、鍵盤,我們只需要知道怎麼使用滑鼠,敲打鍵盤即可,不必知道為何點選滑鼠可以選中、敲打鍵盤是如何輸入文字以及螢幕是如何顯示文字的。總之我們沒必要知道其具體工作細節,只需知道如何使用其提供的功能即可,這就是面向物件。

3.JS的物件組成:方法 和 屬性

在JS中,有函式、方法、事件處理函式、建構函式,其實這四個都是函式,只是作用不同。函式是獨立的存在,方法屬於一個物件,事件處理函式用來處理一個事件,建構函式用來構造物件。

首先通過常用的陣列來認識下JS的物件:

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="UTF-8">
 5         <title></title>
 6         <script>
 7
8 /** 9 * 定義一個數組 10 */ 11 var arr = [1, 2, 3, 4, 5]; 12 13 /** 14 * 彈出 object 15 * 說明陣列就是個物件 16 */ 17 alert(typeof arr); 18 19 /** 20 * 彈出5
21 * 物件的屬性 length 22 */ 23 alert(arr.length); 24 25 /** 26 * 物件的方法 push 27 * 彈出 1,2,3,4,5,6 28 */ 29 arr.push(6); 30 alert(arr); 31 </script> 32 </head> 33 <body> 34 </body> 35 </html>

4.認識下JS中的this以及全域性物件window

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="UTF-8">
 5         <title></title>
 6         <script>
 7             /**
 8              * 定義一個全域性函式
 9              */
10             function show(){
11                 alert(this);
12             }
13             //呼叫show()
14             show();
15             
16         </script>
17     </head>
18     <body>
19     </body>
20 </html>

此處的show()函式為一個全域性函式,呼叫show(),alert(this)彈出來的是window物件,說明全域性函式屬於window。上面定義的show()等於為window新增一個方法,全域性的函式和變數都是屬於window的,上面的定義等價於下面。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <script>
 5             /**
 6              * 為window定義一個show方法
 7              */
 8             window.show = function(){
 9                 alert(this);
10             }
11             //呼叫show()
12             window.show();
13             
14         </script>
15     </head>
16 </html>

同樣的我們也可以根據自己的需求為其它的物件新增方法,比如顯示陣列:

但是我們不能在系統物件中隨意附加方法和屬性,否則可能會覆蓋已有方法、屬性。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <script>
 5             var arr = [1,2,3,4,5];
 6             arr.show = function(){
 7                 alert(this);
 8             }
 9             arr.show(); //彈出 1,2,3,4,5
10         </script>
11     </head>
12 </html>

從上面的例子也可以看出來,this即表示當前函式的呼叫者是誰,但是在一種情況下不是的,就是使用new 來建立物件時,this並不是指向呼叫者的,在後面會有說明。

window是全域性物件,可以看下屬於window的全域性屬性和全域性方法:

二、JS中自定義物件,逐步分析JS中的建立物件

1.通過Object建立簡單物件:

這種方式有一個非常大的弊端,就是如果我有多個人怎麼辦,每次都要新建一個物件,然後新增屬性、方法,這種方式是一次性的,會產生大量重複程式碼,這是不可取的。

 1 <!DOCTYPE html>
 2 <html>
 3     <meta charset="UTF-8" />
 4     <head>
 5         <script>
 6             /**
 7              * 建立一個新物件
 8              * new Object()創建出來的物件幾乎是空白的,需要自己新增屬性,方法
 9              */
10             var person = new Object();
11             //為person物件新增屬性
12             person.name = "jiangzhou";
13             person.age = 22;
14             //為person物件新增方法
15             person.showName = function(){
16                 alert("姓名:"+this.name);
17             }
18             person.showAge = function(){
19                 alert("年齡:"+this.age);
20             }
21             //呼叫物件的方法
22             person.showName();
23             person.showAge();
24             
25         </script>
26     </head>
27 </html>

2.用工廠方式來構造物件:工廠,簡單來說就是投入原料、加工、出廠。

通過建構函式來生成物件,將重複的程式碼提取到一個函式裡面,避免像第一種方式寫大量重複的程式碼。這樣我們在需要這個物件的時候,就可以簡單地創建出來了。

 

 1 <!DOCTYPE html>
 2 <html>
 3     <meta charset="UTF-8" />
 4     <head>
 5         <script>
 6             //建構函式:工廠
 7             function createPerson(name, age){
 8                 var person = new Object();
 9                 
10                 //原料
11                 person.name = name;
12                 person.age = age;
13                 
14                 //加工
15                 person.showName = function(){
16                     alert("姓名:"+this.name);
17                 }
18                 person.showAge = function(){
19                     alert("年齡:"+this.age);
20                 }
21                 //出廠
22                 return person;
23             }
24             //建立兩個物件
25             var p1 = createPerson("jiangzhou", 22);
26             var p2 = createPerson("tom", 20);
27             
28             //呼叫物件方法
29             p1.showName();
30             p1.showAge();
31             
32             p2.showName();
33             p2.showAge();
34             
35         </script>
36     </head>
37 </html>

但是,這種方式有兩個缺點:

①一般我們建立物件是通過new來建立,比如new Date(),這裡使用的是方法建立。使用new來建立可以簡化一些程式碼,也帶來一些新的特性。

②每個物件都有一套自己的方法,浪費資源(雖然對於現在的計算機來說不算什麼,但我們儘量將設計做到最好就行了)。

這裡為什麼說每個物件都有自己的一套方法呢,是因為建立function()的時候其本質是通過new Function()來建立的,會誕生一個新的函式物件,所以每個物件的方法是不一樣的,這樣就存在資源浪費的問題了。看第25行程式碼。

 1 <!DOCTYPE html>
 2 <html>
 3     <meta charset="UTF-8" />
 4     <head>
 5         <script>
 6             
 7             function createPerson(name, age, sex){
 8                 var person = new Object();
 9                 
10                 person.name = name;
11                 person.age = age;
12                 person.sex = sex;
13                 
14                 person.showName = function(){
15                     alert("姓名:"+this.name);
16                 }
17                 person.showAge = function(){
18                     alert("年齡:"+this.age);
19                 }
20                 
21                 /**
22                  *  person.showSex = function(){} 等價於 person.showSex = new Function('');
23                  *  也就是說我們在建立這個函式的時候就是新建了一個物件。
24                  */
25                 person.showSex = new Function('alert("性別:"+this.sex)');
26                 
27                 return person;
28             }
29             
30             //建立兩個物件
31             var p1 = createPerson("jiangzhou", 22, "男");
32             var p2 = createPerson("Lyli", 20, "女");
33             
34             alert(p1.showName == p2.showName); //false
35             
36         </script>
37     </head>
38 </html>

3.使用new 來建立JS物件

 1 <!DOCTYPE html>
 2 <html>
 3     <meta charset="UTF-8" />
 4     <head>
 5         <script>
 6             
 7             function Person(name, age){
 8                 /**
 9                  * 可以假想成系統會建立一個物件
10                  * var this = new Object();
11                  */
12                 
13                 alert(this); //彈出Object
14                 
15                 this.name = name;
16                 this.age = age;
17                 
18                 this.showName = function(){
19                     alert("姓名:"+this.name);
20                 }
21                 this.showAge = function(){
22                     alert("年齡:"+this.age);
23                 }
24                 
25                 /**
26                  * 假想返回了物件
27                  * return this;
28                  */
29             }
30             
31             //建立兩個物件
32             var p1 = new Person("jiangzhou", 22);//可以看到在外面new了在function裡面就不用new了;在function裡面new了,在外面就不用new了;O(∩_∩)O~
33             var p2 = new Person("Lyli", 20);
34             
35             alert(p1.showName == p2.showName); //false
36             
37         </script>
38     </head>
39 </html>

彈出資訊顯示this即是一個Object(第13行程式碼)。在方法呼叫前使用new來建立,function內的this會指向一個新建立的空白物件,而不是指向方法呼叫者,而且會自動返回該物件。

但是這種方式只解決了第一個問題,每個物件還是有自己的一套方法(第35行程式碼)。

 4.在function原型(prototype)上進行擴充套件 —— 最終版

原型新增的方法不會有多個副本,不會浪費資源,所有的物件只有一套方法(看第29行程式碼)。 至於為什麼是用的一套方法呢,看第31行程式碼:因為所有的方法都等於原型上的方法。

 1 <!DOCTYPE html>
 2 <html>
 3     <meta charset="UTF-8" />
 4     <head>
 5         <script>
 6             
 7             /**
 8              * Person建構函式:在JS中,建構函式其實就可以看成類,對某個物件的抽象定義。
 9              * @param {Object} name
10              * @param {Object} age
11              */
12             function Person(name, age){
13                 //屬性:每個物件的屬性各不相同
14                 this.name = name;
15                 this.age = age;
16             }
17             //在原型上新增方法,這樣建立的所有物件都是用的同一套方法
18             Person.prototype.showName = function(){
19                 alert("姓名:"+this.name);
20             }
21             Person.prototype.showAge = function(){
22                 alert("年齡:"+this.age);
23             }
24             
25             //建立兩個物件
26             var p1 = new Person("jiangzhou", 22);
27             var p2 = new Person("Lyli", 20);
28             
29             alert(p1.showName == p2.showName); //true
30             //這裡為什麼兩個物件的方法是相等的呢,可以看成如下
31             alert(p1.showName == Person.prototype.showName); //true
32             
33         </script>
34     </head>
35 </html>

通過prototype我們還可以很方便的擴充套件系統物件,按照自己的需求來擴充套件,而且又能適用於所有地方,又不會浪費資源。如下面對Array進行擴充套件,求陣列和的方法。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="UTF-8">
 5     </head>
 6     <script>
 7         /**
 8          * 對陣列原型擴充套件一個求和的方法;
 9          * 注意不能只加在某個陣列物件上,那樣的話只能在那個物件上適用。
10          */
11         Array.prototype.sum = function(){
12             var sum = 0;
13             for(var i=0;i<this.length;i++){
14                 sum += this[i];
15             }
16             return sum;
17         }
18         //通過new Array() 和 [] 建立陣列完全是一樣的效果。
19         var arr1 = new Array(1,2,3,4,5,6);
20         var arr2 = [11,22,33,44,55];
21         
22         alert(arr1.sum());
23         alert(arr2.sum());
24         
25         alert(arr1.sum == arr2.sum); //true
26         alert(arr2.sum == Array.prototype.sum); //true
27     </script>
28 </html>

 三、案例:JavaScript (例項篇)