1.面向對象的概念
其實面向對象是相對於面向過程而言,通俗來說就是創建對象,每個對象有自身的屬性和方法,對象.屬性 對象.方法 實際上這已經是一個面向對象的過程了,面向過程,是指執行一件事的流程,一步接着一步進行,舉個例子來說,比如你去燒菜,面向過程的執行就是,你先要去買菜,然后你要去洗菜,然后燒菜等一系列具體的步驟,而對於面向對象而言,把你當做一個對象,買菜是一個對象,燒菜也是一個對象,你首先會傳遞消息,你要用菜,菜才就會出現,至於菜是怎么來的,買的還是偷得,那就不需要你知道.......等你洗好會菜會發送消息表明現在要燒菜,菜就會燒好,至於菜是如何燒的,過程如何,你也不需要知道,其實面向過程會細究每一步的執行過程,而面向對象不會細究。
----例子有點不恰當,面向對象的概念本身十分的抽象,只能慢慢體會
2 面向對象的設計模式
一.普通模式
普通模式比較繁瑣,一個對象一個實例,
普通創建對象的方法,缺陷:
- 如果創建多個對象會比較繁瑣,效率低
- 實例與原型之間,沒有任何辦法,可以看出有什么聯系。
例如:
var people=new Object();
people.name="張三";
peoole.food="蘋果";
people.eat=function(){
alert(this.name+"喜歡吃"+this.food)
}
people.eat())//張三喜歡吃蘋果
var people1=new Object();
people1.name="李四";
peoole1.food="香蕉";
people1.eat=function(){
alert(this.name+"喜歡吃"+this.food)
}
people1.eat()//李四喜歡吃香蕉
//若有100個對象,則需要創建100次,不利於實際的開發
二 工廠模式
這種模式比較簡單,其實就是在函數中創建一個對象,給對象添加屬性及其屬性值或屬性方法然后在講這個對象用return返回出來(return 是關鍵)
- 創建過程類似於工廠生產產品的過程,即:原材料--加工--產品...
- 解決了多次重復創建多個對象的麻煩。
- 問題:
- 創建出的實例之間沒有內在的聯系,不能反映出它們是同一個原型對象的實例。
- 創建對象的時候沒有使用 new 關鍵字
- 會造成資源浪費,因為每生成一個實例,都增加一個重復的內容,多占用一些內存。
function create(name,food){
var people=new Object() //原材料;
people.name=nane
people.food=food
people.eat=function(){
alert(this.name+"喜歡吃"+this.food)
}//加工過程
return people;//產品
}
var people 1=create("小丸子",“海鮮”);//不用new關鍵字創建
var people2=create("小李","紅燒肉");
people1.eat()
people2.eat()
//這種模式的缺點就是內存消耗大
people1==people2 //false,占用不同的內存空間
注意:上面提到一定工廠模式一定要有返回值
如果沒有返回,則返回錯誤如下
三. 構造函數模式
- new 調用的函數為構造函數,構造函數和普通函數區別僅僅在於是否使用了new來調用。
- 所謂“構造函數”,就是專門用來生成“對象”的函數。它提供模板,作為對象的基本結構。
- 構造函數內部使用了this變量。對構造函數使用new運算符,就能生成實例,並且this變量會綁定在實例對象上。
- instanceof 驗證原型對象與實例對象之間的關系。
- 使用call和apply方法實現對象的冒充
- 問題:浪費內存--使用構造函數每生成一個實例,都增加一個重復的內容,多占用一些內存。這樣既不環保,也缺乏效率
new關鍵字能改變this的作用域
關鍵采用this關鍵字,對於this的理解,見ttps://www.cnblogs.com/yanhaijing/p/3685309.html(比較厲害的大牛)
function People(name,food){ //構造函數名首字母要大寫,小寫不會錯,但習慣大寫
this.name=name ;
this.food=food;
this.eat=function(){
alert(this.name+"喜歡吃"+this.food)//此處this指的是windows對象
}
}
var people1=new people("張三","蘋果");
var people2=new people("李四","香蕉");
people1.eat()
people1==people2 //false 占用不同的內存空間
小總結:首先函數名首字母應該大寫
與工廠模式不同的是,不需要在函數內部使用關鍵字new,兩者相同的是都消耗很多內存
new關鍵字會改變this的作用域。this為當前調用的對象
創建完成構造函數后需要new一個實例化的對象賦值給一個變量,然后可以通過這個變量來調用構造函數里面的屬性以及方法
構造函數模式可以傳遞參數
四 原型構造模式
構造函數都會有一個prototype(原型)屬性,這個屬性其實就是一個指針,它指向了一個對象,在這個對象里包含了可以共享給實例化對象的所有屬性及方法
1.第一種寫法
function People(){} //定義一個空函數
People.prototype.name="張三";
People.prototype.food="葡萄";
People.prototype.eat=function(){
alert(this.name+"喜歡吃"+this.food)
} //利用prototype屬性來添加屬性值和方法
var people1=new People();//創建實例化對象
var people2=new People();
people1.eat();
people1.eat==people2.eat //true; 判斷是否是相同內存
alert(people1.constructor) //返回構造函數
2 第二種寫法
function People(){}
People.prototype={
name:"小米",
food:" 火鍋",
job :["IT","銷售"],
eat:function(){
alert(this.name+"喜歡吃"+this.food)
}
}
var people1=new People();
people1.job.push("金融");
var people2=new People();
people2.job.push("服務");
alert(people1.job) //彈出為 IT ,銷售,金融,服務
alert(people2.job) //彈出為 IT ,銷售,金融,服務(由於兩者地址相同,所以無論哪一方在向數組中添加,都會全部顯示出來)
小總結:原型模式過於呆板,內容定義只能唯一,如果改變其中的屬性值,則全部都會改變,沒有使用this活潑,內存如果想修改其中一個實例化對象的屬性或方法另一個實例對象也會隨改變,這並非我們想要的結果,所以就會誕生了混合模式。
補充:
- prototype方式定義的方式,函數不會拷貝到每一個實例中,所有的實例共享prototype中的定義,節省了內存。
- Prototype模式的驗證方法
- isPrototypeOf()這個方法用來判斷,某個proptotype對象和某個實例之間的關系。
- hasOwnProperty()每個實例對象都有一個hasOwnProperty()方法,用來判斷某一個屬性到底是本地屬性,還是繼承自prototype對象的屬性。
- in運算符in運算符可以用來判斷,某個實例是否含有某個屬性,不管是不是本地屬性。in運算符還可以用來遍歷某個對象的所有屬性。
- 對象的constructor屬性用於返回創建該對象的構造函數.
- 原型方式的問題:
- 構造函數沒有參數。使用原型方式,不能通過給構造函數傳遞參數來初始化屬性的值
- 屬性指向的是對象,而不是函數時。函數共享不會造成問題,但對象卻很少被多個實例共享,如果共享的是對象就會造成問題
五 混合模式(構造函數模式+原型模式)
//構造函數模式可以傳遞參數,而且使用this關鍵字,活動性很強,但消耗內存過多
//原型模式消耗內存小,但活動性很差,因此兩者合並,當需要傳遞參數時,則使用構造函數,當需要執行方法時,使用原型模式,
這是目前最為常用的創建對象的方式。
這種概念非常簡單,即用構造函數定義對象的所有非函數屬性,用原型方式定義對象的函數屬性(方法)。結果是,所有函數都只創建一次,而每個對象都具有自己的對象屬性實例。
此外,組合模式還支持向構造函數傳遞參數,可謂是集兩家之所長。
在所接觸的JS庫中,jQuery類型的封裝就是使用組合模式來實例的!!!
function People(name,food){
this.name=name;
this.food=food;
}
People.prototype={
eat:function(){
alert(this.name+"喜歡吃"+this.food)
}
}
var people1=new People("小明","雞蛋");
var people2=new People(“張三”,“水餃”)
people1.eat();
people2.eat();
people1.eat==people2.eat //true (eat屬性屬於原型模式,內存相同)
people1.name==people2.name //flase (name屬於構造函數屬性,內存不同)
六 動態模式
function People(name,food){
this.name=name;
this.food=food;
if(typeof this.eat!='function'){
alert("程序開始");
People.prototype.eat=function(){
alert(this.name+"喜歡吃"+this.food)
}
}
}
var people1=new People("小明","雞蛋");
var people2=new People("小紅","餃子");
people1.eat()
people2.eat();
//執行結果圖:
有執行結果圖看出動態模式更好的讓我們避免創建對象多次初始化
詳細代碼見:(明天上傳github)
有理解不正確的地方,希望大神們指點!
我的博客即將搬運同步至騰訊雲+社區,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=1v9cvnavta0pn