JavaScript面向對象(OOP)


  前  言

JRedu

       面向對象程序設計(簡稱OOP)是現在最流行的程序設計方法,這種方法有別於基於過程的程序設計方法。在寫面向對象的WEB應用程序方面JavaScript是一種很好的選擇.它能支持OOP.因為它通過原型支持繼承的方式和通過屬性和方法的方式一樣好.很多開發者試圖拋棄JS,試着用C#或JAVA僅是因為JS不是他認為合適的面向對象的語言.許多人還沒有認識到javascript支持繼承.當你寫面向對象的代碼時.它能給你很強大的能量.你也可以使用它寫出可復用,可封裝的代碼.

 

一、什么是面向對象編程(OOP)?

        在了解什么是面向對象編程之前,我們來看看語言的分類。總體可以分為三類:面向機器面向過程還有面向對象。面向對象的語言主要有C++、Java、PHP等。

1面向過程與面向對象    

1)面向過程:面向過程專注於如何去解決一個問題的過程步驟。編程特點是由一個個函數去實現每一步的過程步驟,沒有類和對象的概念。
2)面向對象:專注於由哪一個對象來解決這個問題,編程特點是出現了一個類,從類中拿到對象,由這個對象去解決具體問題。
         對於調用者來說,面向過程需要調用者自己去實現各種函數。而面向對象,只需要告訴調用者,對象中具體方法的功能,而不需要調用者了解方法中的實現細節。

2面向對象的三大特征

      這個對於計算機專業的人來說,相信大家已經很熟悉啦,那我就再說一遍吧~

      面向對象的三大特征是繼承、封裝、多態。JS可以模擬實現繼承和封裝,但是無法模擬實現多態,所以我們說JS是一門基於對象的語言,而非是面向對象的語言。

3類和對象

 

1、類:一類具有相同特征(屬性)和行為(方法)的集合。
比如,人類具有身高、體重等屬性,吃飯、大笑等行為,所以,我們可以把人划分為一類。


2、對象:從類中,拿出具有確定屬性值和方法的個體。
比如,張三-->屬性:身高180體重180 方法:說話-->我叫張三,身高180

3、類和對象的關系:
①類是抽象的,對象是具體的(類是對象的抽象化,對象是類的具體化)

②類是一個抽象的概念,只能說類有屬性和方法,但是不能給屬性賦具體的。比如,人類有姓名,但是不能說人類的姓名叫什么。
   對象是一個具體的個例,是將類中的屬性進行具體賦值而來的個體。
比如,張三是一個人類的個體。可以說張三的姓名叫張三。也就是張三對人類的每一個屬性進行了具體的賦值,那么張三就是由人類產生的一個對象。

4、使用類和對象的步驟:

1)創建一個類(構造函數):類名必須使用大駝峰法則。即每個單詞首字母都要大寫

function 類名(屬性1){
     this.屬性1=屬性1;
     this.方法=function(){
      //方法中要調用自身屬性,必須使用this.屬性
     }
}

2)通過類實例化(new)出一個對象。

var obj=new 類名(屬性1的具體值);
obj.屬性; 調用屬性
obj.方法; 調用方法

3)注意事項
①通過類名,new出一個對象的過程,叫做"類的實例化"。
②類中的this,會在實例化的時候,指向新new出的對象。
所以,this.屬性 this.方法實際上是將屬性和方法綁定在即將new出的對象上面。
③在類中,要調用自身屬性,必須使用this.屬性名。如果直接使用變量名,則無法訪問對應的屬性。

function Person(name,age){
   this.name=name;
   this.age=age;
   this.say=function(content){
       //在類中,訪問類自身的屬性,必須使用this.屬性調用。
       alert("我叫"+this.name+",今年"+this.age+"歲,我說了一句話:"+content);
   }
}
var zhangsan=new Person("姐姐",18);
zhangsan.say("你好呀");

④類名必須使用大駝峰法則,注意與普通函數區分。

4面向對象的兩個重要屬性

1)constructor:返回當前對象的構造函數。
>>>zhangsan.constructor==Person;  ( true)
2)instanceof:檢測一個對象是不是一個類的實例;
>>>lisi instanceof Person              √ lisi是通過Person類new出的
>>>lisi instanceof Object              √ 所有對象都是Object的實例
>>>Person instanceof Object        √ 函數本身也是對象

5廣義對象與狹義對象

1)狹義對象:只有屬性和方法,除此之外沒有任何其他內容。

 

var obj={};  //用{}聲明的對象
var obj=new Object(); //用new聲明的對象

 

2)廣義對象:除了用字面量聲明的基本數據類型之外,JS中萬物皆對象。換句話說,只要能添加屬性和方法的變量,都可以稱為對象。

var s="123";  //不是對象
s.name="aaa";
console.log(typeof(s)); //String
console.log(s.name); //undfined 字面量聲明的字符串不是對象,不能添加屬性
var s=new String("123");  //是對象
s.name="aaa";
console.log(typeof(s)); //Object
console.log(s.name); //"aaa" 使用new聲明的字符串是對象,能添加屬性和方法。

 

二、 成員屬性、靜態屬性和私有屬性

1、在構造函數中,使用this.屬性聲明。或者在實例化出對象以后,使用"對象.屬性"追加的,都屬於成員屬性成員方法。也叫實例屬性或實例方法。
     成員屬性/方法,是屬於由類new出的對象的。
     需要使用"對象名.屬性名"調用。

【靜態屬性與靜態方法】
2、通過“類名.屬性名”、“類名.方法名”聲明的屬性和方法,稱為靜態屬性靜態方法。也叫類屬性和類方法。
     類屬性/類方法,是屬於類的(屬於構造函數的)
     通過"類名.屬性名"調用。

3、成員屬性是屬於實例化出的對象的,只能使用對象調用。
靜態屬性是屬於構造函數的,只能使用類名調用。

[私有屬性和私有方法]
4、在構造函數中,使用var聲明的變量稱為私有屬性;
在構造函數中,使用function聲明的函數,稱為私有方法;

function Person(){
    var num=1;//私有屬性
    function func(){}//私有方法
}

私有屬性和私有方法的作用域,只在構造函數內容有效。即只能在構造函數內部使用,在構造函數外部,無論使用對象名還是類名都無法調用。

 

function Person(name){
    this.name=name; //聲明成員屬性
    var sex="男";//私有屬性
                
}
            
var zhangsan=new Person("張三");
zhangsan.age=14; //追加成員屬性
alert(zhangsan.name); //調用成員屬性
            
Person.count="60億"; //聲明靜態屬性
alert(Person.count); //調用靜態屬性
var lisi=new Person("李四");
console.log(lisi.count);
//undefined 靜態屬性是屬於類的,只能用類名調用。

 

三、 JavaScript模擬實現封裝

1、什么叫封裝?
①方法的封裝:將類內部的函數進行私有化處理,不對外提供接口,無法在類外部使用的方法,稱為私有方法,即方法的封裝。
②屬性的封裝:將類中的屬性進行私有化處理,對外不能直接使用對象名訪問(私有屬性)。同時,需要提供專門用於設置和讀取私有屬性的set/get方法,讓外部使用我們提供的方法,對屬性進行操作。這就叫屬性的封裝。
2、注意:封裝不是拒絕訪問,而是限制訪問。要求調用者,必須使用我們提供的set/get方法進行屬性的操作,而不是直接拒絕操作。
因此,單純的屬性私有化,不能稱為封裝!必須要有私有化后,提供對應的set/get方法。

function Person(name,age1){
    this.name=name;
// this.age=age; var age=0; this.setAge=function(ages){ if(ages>0&&ages<=120){ age=ages; }else{ alert("年齡賦值失敗"); } } // 當實例化類拿到對象時,可以直接通過類名的()傳入年齡,設置私有屬性 if(age1!=undefined) this.setAge(age1); this.getAge=function(){ return age; } this.sayTime=function(){ alert("我說當前時間是:"+getTime()); } this.writeTime=function(){ alert("我寫了當前時間是:"+getTime()); }
/*私有化的方法,只能在類內部被其他方法調用,而不能對外提供功能。這就是方法的封裝*/ function getTime(){ return new Date(); } } var zhangsan=new Person("張三",99); zhangsan.setAge(99); alert("張三的年齡是"+zhangsan.getAge()); var lisi=new Person("李四",99); lisi.setAge(110); alert("李四的年齡是:"+lisi.getAge());

 

四、JavaScript中的this指向詳解

1、誰最終調用函數,this最終指向誰(記住!)
①this指向誰,不應考慮函數在哪聲明,而應該考慮函數在哪調用!!!
②this指向的永遠只可能是對象,而不可能是函數。
③this指向的對象,叫做函數的上下文context,也叫函數的調用者。


2、this指向的規律!!!(跟函數的調用方式息息相關,記住這點,相信你一定會分清this指向噠)
①通過函數名()調用的,this永遠指向window
②通過對象.方法調用的,this指向這個對象。
③函數作為數組中的一個元素,用數組下標調用的,this指向這個數組
④函數作為window內置函數的回調函數使用,this指向window。
setInterval setTimeout 等。
⑤函數作為構造函數,使用new關鍵字調用,this指向新new出的對象。

function func(){
    console.log(this);
}
var obj={
    name:"zhangsan",
    func:func
}
//①通過函數名()調用的,this永遠指向window。
func();
//②通過對象.方法調用的,this指向這個對象
obj.func();//狹義對象
            
window.onclick=function(){
    document.getElementById("div1").onclick=function(){
        func();//最終還是使用()調用,所以指向window
    }
    document.getElementById("div1").onclick=func;//廣義對象,指向div
}
//③函數作為數組中的一個元素,用數組下標調用的,this指向這個數組
var arr=[1,2,3,func,4,5,6];
arr[3]();
            
//④函數作為window內置函數的回調函數使用,this指向window。
setTimeout(func,1000);
            
//⑤函數作為構造函數,使用new關鍵字調用,this指向新new出的對象。
var obj1=new func();

現在,你一定分清了this指向了吧,下面我們來看一個綜合案例:

var obj1={
    name:"obj1",
    arr:[func,1,{name:"obj2",func:func},3,4],
}
obj1.arr[0]();//最終的調用者是數組。this-->obj.arr
setTimeout(obj1,arr[0],2000);//obj.arr[0]僅僅是取到函數賦給setTimeout,但並沒有調用。函數的最終調用者是setTimeout。這個式子相當於setTimeout(func,2000);
obj1.arr[2].func();//最終調用者是{name:"obj2",func:func}
setTimeout(obj1.arr[2].func,2000);//最終調用者是setTimeout
            
//↓最終的調用者是div1
//document.getElementById("div1").onclick=obj1.arr[0]; //document.getElementById("div1").onclick=arr[2].func;

最后,我們再來看一道面試題:

var fullname = 'John Doe';
var obj = {
   fullname: 'Colin Ihrig',
   prop: {
      fullname: 'Aurelio De Rosa',
      getFullname: function() {
         return this.fullname;
      }
   }
};
console.log(obj.prop.getFullname()); 
// 函數的最終調用者 obj.prop 
            
var test = obj.prop.getFullname;
console.log(test());  
// 函數的最終調用者 test()  this-> window
            
obj.func = obj.prop.getFullname;
console.log(obj.func()); 
// 函數最終調用者是obj
            
var arr = [obj.prop.getFullname,1,2];
arr.fullname = "JiangHao";
console.log(arr[0]());
// 函數最終調用者數組

這次就分享到這了,下次再介紹JS中OOP中的繼承方法吧~


免責聲明!

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



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