Javascript 面向對象編程—繼承和封裝

  前  言前端

 Javascript是一種基於對象(object-based)的語言,你遇到的全部東西幾乎都是對象。可是,它又不是一種真正的面向對象編程(OOP)語言,由於它的語法中沒有class(類)。面向對象主要專一於有哪個對象來解決這個問題,編程特色時出現一個個的類,從類中拿到對象,有這個對象去解決具體問題。 對於調用者來講,面向過程須要調用者去實現各類函數。而面向對象,只須要告訴調用者對象中的具體方法的功能, 而不須要調用者瞭解方法中的實現細節。編程

 而面向過程主要專一於如何去解決一個問題的步驟。編程特色是由一個個的函數去實現每一步的過程步驟,沒有類和對象的概念。app

 

1、 繼承

咱們首先解釋一下繼承的概念,所謂繼承就是使用一個子類,繼承另外一個父類,那麼子類能夠自動擁有父類中的全部屬性和方法,這個過程叫繼承,繼承的兩方,發生在兩個類間。函數

而後咱們闡述一下實現繼承的原理, 經過循環將父類對象的全部屬性,所有賦給子類對象。關鍵點在於for-in循環, 即便不擴展循環Object,也能經過簡單的循環實現操做
  學習

1.1擴展Object實現繼承。

 

 1 function Person(name,age){
 2                 this.name=name;
 3                 this.age=age;
 4                 this.say=function(){
 5                     alert("我叫"+this.name);
 6                 }
 7             }
 8             
 9             function Student(no){
10                 this.no=no;
11                 this.study=function(){
12                     alert("我在學習");
13                 }
14             }
15             
16             var p=new Person("張三",12);
17             var s=new Student("12345");
18             for(var i in p){
19                 s[i]=p[i];
20             }
21             
22             Object.prototype.extend1=function(){
23                 for(var i in parent){
24                     this[i]=parent[i];
25                 }
26             }
27             s.extend1(p);
28             
29             console.log(s);

可是呢,擴展Object繼承也有以下缺點:
① 沒法經過一次實例化,拿到完整的子類對象,而須要先拿到父類對象和子類對象兩個對象,手動合併
② 擴展Object繼承方法,也會保留在子類對象上this

 

1.2使用原型實現繼承

咱們先說說使用原型繼承的原理, 將父類對象,賦值給子類的prototype,那麼父類對象的屬性和方法就會出如今子類的prototype中。  那麼,實例化子類時,子類的prototype又不會到子類對象的__proto__中,  最終,父類對象的屬性和方法,會出如今子類對象的__proto__spa


這種繼承的特色主要是,子類自身的全部屬性,都是成員屬性,父類繼承過來的屬性,都是原型屬性,可是依然沒法經過一次實例化拿到全部的子類對象。prototype

 1 function Person(name,age){
 2                 this.name=name;
 3                 this.age=age;
 4                 this.say=function(){
 5                     alert("我叫"+this.name);
 6                 }
 7             }
 8             
 9             function Student(no){
10                 this.no=no;
11                 this.study=function(){
12                     alert("我在學習");
13                 }
14             }
15             
16             Student.prototype=new Person("張三",12);
17             var s=new Student(15);
18             console.log(s);

 

1.3使用call和apply以及bind實現繼承

咱們先解釋一下call/bind/apply三個函數的做用,這三個函數經過函數名調用這三個函數,能夠強行將函數中的this指定爲某個對象。code

 

 1 var name="window"
 2             function func(a,b){
 3                 console.log(this.name+a+b);
 4             }
 5             var obj={
 6                 name:"zhangsan"
 7             }
 8             var obj1={
 9                 name:"lisi"
10             }
11             func(1,2);//window12
12             func.call(obj,1,2);//zhangsan12
13             func.apply(obj1,[1,2]);//lisi12
14             func.bind(obj)(1,2);//zhangsan12
15             
16             
17             function Person(name,age){
18                 this.name=name;
19                 this.age=age;
20                 this.say=function(){
21                     alert("我叫"+this.name);
22                 }
23             }
24             
25             function Student(no,name,age){
26                 this.no=no;
27                 this.study=function(){
28                     alert("我在學習");
29                 }
30                 Person.call(this,name,age);
31             }
32             var s=new Student(12345,"張三",15);
33             console.log(s);

這三個函數的惟一區別,在於接受func參數列表的方式不一樣,除此以外,功能上無區別。對象

 

2、 封裝

什麼叫封裝呢?封裝分爲方法的封裝和屬性的封裝。
所謂 方法的封裝就是將類內部的函數進行私有化處理,不對外提供調用接口,沒法在類外部使用的方法,稱爲私有方法,即方法的封裝。

而屬性的封裝: 將類中的屬性進行私有化處理,對外不能直接使用對象名訪問(私有屬性)。 同時,須要提供專門用於設置和讀取私有屬性的set/get方法,讓外部使用咱們提供的方  法,對屬性進行操做。 這就叫屬性的封裝。

封裝也有須要 注意的地方, 封裝不是拒絕訪問,而是限制訪問。  要求調用者,必須使用咱們提供的set/get方法進行屬性的操做,而不是直接拒絕操做。 

所以,單純的屬性私有化,不能稱爲封裝!必需要私有化以後,提供對應的set/get方法。

 

一、 生成實例對象的原始模式

 

1.1咱們把人看作一個對象,人有"姓名"和"年齡"兩個屬性。

 

1 var Person={
2 
3       name : "張三",
4 
5       age : "12"    
6   
7 }

 

1.1咱們根據這個原型對象的模式,生成兩個實例對象。

 

1  var Person1= {}; // 建立一個空對象
2         Person1.name = "張三"; // 按照原型對象的屬性賦值
3         Person1.age= "12";
4  var Person2= {};
5         Person2.name = "李四";
6         Person2.age= "15"; 
7 
8 //這就是最簡單的封裝了,把兩個屬性封裝在一個對象裏面。       

 

二、 原始對象模式的改進

 

1  function Person(name,age) {
2     return {
3       name:name,
4       age:age    
5            }
6  }
7 
8  var Person1= Person("張三","12");
9  var Person2= Person("李四","15");

 

三、 構造函數

構造函數:其實就是一個普通函數,可是內部使用了this變量。對構造函數使用new運算符,就能生成實例,而且this變量會綁定在實例對象上。

咱們來講說建立一個類和對象的大概步驟,

首先,建立一個類(構造函數):類名必須使用大駝峯法則。即每一個單詞首字母大寫。

function 類名(屬性1){
    this.屬性1=屬性1;
    this.方法=function(){
     //方法中要調用自身屬性,必須使用this.方法
    }
   }
   經過類,實例化(new)出一個對象。
   var obj=new 類名(屬性1的具體值);
   obj.屬性; //調用屬性
   obj.方法(); //調用方法

 

 1 //人的原型對象
 2  function Person(name,age){
 3     this.name=name;
 4     this.age=age;
 5  }
 6 
 7 //生成實例對象
 8  var Person1= new Person("張三","12");
 9  var Person2= new Person("李四","15");
10  console.log(Person1.name); // 張三
11  console.log(Person2.age); // 15
12 
13 //Person1 和 Person2都會有一個constructor屬性,返回當前對象的構造函數
14  console.log(Person1 .constructor == Person); //true
15  console.log(Person2 .constructor == Person); //true
16 
17 //instanceof檢測一個對象是否是一個類的實例
18  console.log(Person1 instanceof Person); //true
19  console.log(Person2 instanceof Person); //true

構造函數須要注意如下幾點,
一、經過一個類名,new出一個對象的過程,叫作"類的實例化"
二、類中的this,會在實例化的時候指向新的new出的對象
因此,this.方法this.屬性,其實是將屬性和方法綁定在即將new出的對象上,在類中調用自身屬性,必須使用this.屬性名。若是直接使用變量名,則沒法訪問對應的屬性。 類名必須使用大駝峯法則,注意區分與普通函數的區別。
   

四、 Prototype模式

 

prototype 屬性容許您向對象添加屬性和方法,每個構造函數都有一個prototype屬性,指向另外一個對象。這個對象的全部屬性和方法,都會被構造函數的實例繼承。

1  function Person(name,age){
2         this.name=name;        
3         this.age=15;
4  }
5  Person.prototype.age=12;            
6  var zhangsan=new Person("張三");
7  console.log(zhangsan.age);        

 

編者按

  Javascript面向對象是最難的,初學者不容易掌握,能夠多多參考參考專門Javascript面向對象的資料,最後,但願各位和小編一塊兒努力,在前端的路上越走越遠!

相關文章
相關標籤/搜索