前 言javascript
JRedujava
面向對象程序設計(簡稱OOP)是如今最流行的程序設計方法,這種方法有別於基於過程的程序設計方法。在寫面向對象的WEB應用程序方面JavaScript是一種很好的選擇.它能支持OOP.由於它經過原型支持繼承的方式和經過屬性和方法的方式同樣好.不少開發者試圖拋棄JS,試着用C#或JAVA僅是由於JS不是他認爲合適的面向對象的語言.許多人尚未認識到javascript支持繼承.當你寫面向對象的代碼時.它能給你很強大的能量.你也可使用它寫出可複用,可封裝的代碼.面試
1、什麼是面向對象編程(OOP)? |
在瞭解什麼是面向對象編程以前,咱們來看看語言的分類。整體能夠分爲三類:面向機器、面向過程還有面向對象。面向對象的語言主要有C++、Java、PHP等。編程
1)面向過程:面向過程專一於如何去解決一個問題的過程步驟。編程特色是由一個個函數去實現每一步的過程步驟,沒有類和對象的概念。
2)面向對象:專一於由哪個對象來解決這個問題,編程特色是出現了一個類,從類中拿到對象,由這個對象去解決具體問題。
對於調用者來講,面向過程須要調用者本身去實現各類函數。而面向對象,只須要告訴調用者,對象中具體方法的功能,而不須要調用者瞭解方法中的實現細節。數組
這個對於計算機專業的人來講,相信你們已經很熟悉啦,那我就再說一遍吧~函數
面向對象的三大特徵是繼承、封裝、多態。JS能夠模擬實現繼承和封裝,可是沒法模擬實現多態,因此咱們說JS是一門基於對象的語言,而非是面向對象的語言。this
一、類:一類具備相同特徵(屬性)和行爲(方法)的集合。
好比,人類具備身高、體重等屬性,吃飯、大笑等行爲,因此,咱們能夠把人劃分爲一類。spa
二、對象:從類中,拿出具備肯定屬性值和方法的個體。
好比,張三-->屬性:身高180體重180 方法:說話-->我叫張三,身高180
三、類和對象的關係:
①類是抽象的,對象是具體的(類是對象的抽象化,對象是類的具體化)
②類是一個抽象的概念,只能說類有屬性和方法,可是不能給屬性賦具體的。好比,人類有姓名,可是不能說人類的姓名叫什麼。
對象是一個具體的個例,是將類中的屬性進行具體賦值而來的個體。
好比,張三是一我的類的個體。能夠說張三的姓名叫張三。也就是張三對人類的每個屬性進行了具體的賦值,那麼張三就是由人類產生的一個對象。
四、使用類和對象的步驟:設計
1)建立一個類(構造函數):類名必須使用大駝峯法則。即每一個單詞首字母都要大寫code
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("你好呀");
④類名必須使用大駝峯法則,注意與普通函數區分。
1)constructor:返回當前對象的構造函數。
>>>zhangsan.constructor==Person; ( true)
2)instanceof:檢測一個對象是否是一個類的實例;
>>>lisi instanceof Person √ lisi是經過Person類new出的
>>>lisi instanceof Object √ 全部對象都是Object的實例
>>>Person instanceof Object √ 函數自己也是對象
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聲明的字符串是對象,能添加屬性和方法。
2、 成員屬性、靜態屬性和私有屬性 |
一、在構造函數中,使用this.屬性聲明。或者在實例化出對象之後,使用"對象.屬性"追加的,都屬於成員屬性或成員方法。也叫實例屬性或實例方法。
成員屬性/方法,是屬於由類new出的對象的。
須要使用"對象名.屬性名"調用。
【靜態屬性與靜態方法】
二、經過「類名.屬性名」、「類名.方法名」聲明的屬性和方法,稱爲靜態屬性、靜態方法。也叫類屬性和類方法。
類屬性/類方法,是屬於類的(屬於構造函數的)
經過"類名.屬性名"調用。
三、成員屬性是屬於實例化出的對象的,只能使用對象調用。
靜態屬性是屬於構造函數的,只能使用類名調用。
[私有屬性和私有方法]
四、在構造函數中,使用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 靜態屬性是屬於類的,只能用類名調用。
3、 JavaScript模擬實現封裝 |
一、什麼叫封裝?
①方法的封裝:將類內部的函數進行私有化處理,不對外提供接口,沒法在類外部使用的方法,稱爲私有方法,即方法的封裝。
②屬性的封裝:將類中的屬性進行私有化處理,對外不能直接使用對象名訪問(私有屬性)。同時,須要提供專門用於設置和讀取私有屬性的set/get方法,讓外部使用咱們提供的方法,對屬性進行操做。這就叫屬性的封裝。
二、注意:封裝不是拒絕訪問,而是限制訪問。要求調用者,必須使用咱們提供的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());
4、JavaScript中的this指向詳解 |
一、誰最終調用函數,this最終指向誰(記住!)
①this指向誰,不該考慮函數在哪聲明,而應該考慮函數在哪調用!!!
②this指向的永遠只多是對象,而不多是函數。
③this指向的對象,叫作函數的上下文context,也叫函數的調用者。
二、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中的繼承方法吧~