js中的面向對象入門
什麼是對象
我們先來看高程三中是如何對對象進行定義的
"無序屬性的集合,其屬性可以包括基本值、對象或者函數",對象是一組沒有特定順序的的值。對象的沒個屬性或方法都有一個俄名字,每個名字都映射到一個值。
簡單來理解對象就是由屬性和方法來組成的
面向對象的特點-封裝
對於一些功能相同或者相似的代碼,我們可以放到一個函數中去,多次用到此功能時,我們只需要調用即可,無需多次重寫。
在這裡我們可以理解為創造對象的幾種模式:單例模式,工廠模式,構造函數模式,原型模式等。
繼承
子類可以繼承父類的屬性和方法
- 多態(重載和重寫)
- 重載:嚴格意義上說js中沒有重載的功能,不過我們可以通過判斷函數的參數的不同來實現不同的功能來模擬重載。
- 重寫:子類可以改寫父類的屬性和方法
javascript中的封裝
單例模式
var a = 1;
function getNum{
return 1;
}
後來公司又招了個前端小明,於是變成他們2個一起寫同一個js了。一天小王發現自己寫的getNum方法出問題了,原來是小華寫的js中也有個getNum的函數,代碼合并後把他的覆蓋掉了,於是便找小華理論去,經過一番妥協後,兩人都把自己的代碼改了改
var xiaoming = {
num:1,
getNum:function{
return 1;
}
}
var xiaohua = {
num:2,
getNum: function{
return 2;
}
}
這就是我們所謂的單例模式(命名空間)
我們把描述同一個事物的方法或者屬性放到同一個對象里,不同事物之間的方法或者屬性名相同相互也不會發生衝突。
單例模式的優劣
使用單例模式,我們可以實現簡單的模塊化開發
var utils = { getCss:function{ //code }, getByClass:function{ //code }, setCss:function{ //code } }
- 避免了全局變數名的衝突
- 缺點:
- 單例模式只是一定程度上避免了變數名的衝突,但並不能徹底解決此問題,而且在不同的對象下,我們可能會有很多功能相同的代碼,最終造成大量的冗餘代碼。
- 單例模式讓每個對象有了自己獨立的命名空間,但是並不能批量生產的問題,每一個新的對象都要重新寫一份一模一樣的代碼。
var person1 = {
name:"小明",
age:24,
showName:function{
console.log("我的名字是:"+this.name)
}
};
var person1 = {
name:"小華",
age:25,
showName:function{
console.log("我的名字是:"+this.name)
}
};
工廠模式
- 工廠模式其實就是把需要一個個的編寫的對象,放在一個函數中統一的進行創建,說白了就是普通函數的封裝。
- 工廠模式總共3步驟:
function CreatePerson(name,age){
var obj={};//1.創建一個空對象
//2.加工對象
obj.name=name;
obj.age=age;
obj.showName=function{
console.log("我的名字是:"+this.name)
};
return obj;//3.輸出對象;
}
var person1 = CreatePerson("小明",23)
var person2 = CreatePerson("小華",23)
person1.showName; //我的名字是:小明
person2.showName; //我的名字是:小華
- 工廠模式的優缺點
- 既然叫工廠模式,它就和我們周圍的工廠一樣,我們只需要把原材料放進去,就能得到我們需要的產品了。
- 工廠模式也解決了單例模式的批量生產的問題,避免了單例模式中的大量冗餘代碼,進行系統的封裝,提高代碼的重複利用率
- 不過工廠模式跟我們js內置類的調用方法不同
構造函數模式
- 可以創建一個自定義的類,並且可以new出實例
- 構造函數做的就是類和實例打交道。
//構造函數:首字母大寫(約定俗成);
function CreatePerson(name,age){ //創建一個自定義的類
//構造函數中的this,都是new出來的實例
//構造函數中存放的都是私有的屬性和方法;
this.name=name;
this.age=age;
this.showName=function{
console.log("我的名字是:"+this.name)
}
}
//實例1
var person1 = new CreatePerson("小明",25)
//實例2
var person2 = new CreatePerson("小華",24)
這裡說一下工廠模式和構造函數模式的區別:
1. 在調用的時候不同:
工廠模式:調用的時候,只是普通函數的調用createPerson;
構造函數模式:new CreatePerson;
2. 在函數體內不同:
工廠模式有三步:1)創建對象 2)加工對象 3)返回對象;
構造函數模式只有1步: 只有加工對象; 因為系統默認會為其創建對象和返回對象;
3. 構造函數默認給我們返回了一個對象,如果我們非要自己手動返回的話:
(1)手動返回的是字元串類型:對以前實例上的屬性和方法沒有影響;
(2)手動返回的是引用數據類型:以前實例身上的屬性和方法就被覆蓋了;實例無法調用屬性和方法;
構造函數的方法都是私有方法,每個實例調用的都是自己私有的方法,同樣也會有許多重複的代碼。
我們可以使用原型模式來解決每個實例中都有相同方法的函數的問題
原型模式
function CreatePerson(name,age){
this.name=name;
this.age=age;
}
// 我們把公有的方法放到函數的原型鏈上
CreatePerson.prototype.showName = function{
console.log("我的名字是:"+this.name)
}
var person1 = new CreatePerson("小明",25)
var person2 = new CreatePerson("小華",24)
person1.showName //小明
原型模式的關鍵:
1)每個函數數據類型(普通函數,類)上,都有一個屬性,叫prototype。
2)prototype這個對象上,天生自帶一個屬性,叫constructor:指向當前這個類;
3)每個對象數據類型(普通對象,prototype,實例)上都有一個屬性,
叫做__proto__:指向當前實例所屬類的原型;
這3句話理解了,下邊的東西就可以不用看了 //手動滑稽
通過例子我們來看這幾句話是什麼意思
function CreatePerson(name,age){
this.name=name;
this.age=age
}
CreatePerson.prototype.showName=function{
console.log("我的名字是:"+this.name)
}
var person1 = new CreatePerson("小明",25);
console.dir(person1)
在chrome瀏覽器控制台中顯示
從圖中可以看出,person1這個對象上有name和age兩個屬性,
person1的__proto__指向了它的構造函數(CreatePerson)的prototype上,
而且還有一個showName的方法。
並且它們中有一條鏈關聯著: person1.__proto__ === CreatePerson.prototype
接著來看
```
function Foo{
this.a=1;
}
Foo.prototype.a=2;
Foo.prototype.b=3;
var f1 = new Foo; //沒有參數的話括弧可以省略
console.log(f1.a) //1
console.log(f1.b) // 3
以這個為例,
當我們查找f1.a時,因為f1中有這個屬性,所以我們得出 f1.a=1;
當我們查找f1.b時,f1中沒有這個屬性,我們便順著f1.__proto__這條鏈去
它的構造器的prototype上找,所以我們得出了 f1.b = 3;

接著來說,Foo.prototype是個對象,那麼它的\_\_proto\_\_指向哪裡呢
還記的剛剛說的那句
**每個對象數據類型(普通對象,prototype,實例)上都有一個屬性,叫做\_\_proto\_\_:指向當前實例所屬類的原型**
此外,我們應該知道
**每一個對象都是function Object這個構造函數的實例**

所以我們可以接著還原這個原型圖

等等,圖上貌似多了個個Object.prototype.\_\_proto\_\_ 指向了null,這是什麼鬼?
> 我們這麼來理解,Object.prototype是個對象,
那麼它的\_\_proto\_\_指向了它的構造函數的prototype上,
最後發現了還是指向它自身,這樣轉了個圈貌似是無意義的,於是便指向了null
還沒完,我們發現對象都是函數(構造器)創造出來的,那麼函數是誰創造的呢?石頭裡蹦出來的么?
**在js中,function都是由function Function這個構造器創造的,每一個函數都是Function的實例**

現在基本上我們就能得出了完整的原型圖了

是不是有點亂?根據我們剛剛講的是能把這個圖理順的,
這裡需要注意下,Function.\_\_proto\_\_是指向它的prototype的
多說一點,判斷數據類型的方法時,我們知道有個instanceof的方法
比如
A instanceof B
instanceof判斷的規則就是:
> 沿著A的\_\_proto\_\_這條線查找的同時沿著B的prototype這條線來找,如果兩條線能找到同一個引用(對象),那麼就返回true。如果找到終點還未重合,則返回false。
再來看我們之前的那個例子
```
function Foo{
this.a=1;
}
Foo.prototype.a=2;
Foo.prototype.b=3;
var f1 = new Foo; //沒有參數的話括弧可以省略
console.log(f1.a) //1
console.log(f1.b) // 3
當我們查找f1.a時,因為f1中有這個屬性,所以我們得出 f1.a=1;
當我們查找f1.b時,f1中沒有這個屬性,我們便順著f1.__proto__這條鏈去它的構造器的prototype上找,所以我們得出了 f1.b = 3;
當我們查找一個對象的屬性時,先在這個對象的私有空間內查找,如果沒找到,就順著對象的__proto__這條鏈去它的構造器的ptototype上查找,如果還沒找到,接著沿__proto__向上查找,直到找到Object.prototype還沒有的話,這個值就為undefined,這就是所謂的原型鏈
列舉下網頁中的一些相關的原型鏈
有興趣的同學可自行通過瀏覽器控制台看看我們常用的方法都是在哪個類上定義的,比如getElementsByTagName,addEventListener等等
繼承在這裡就主要說一下組合繼承(call + 原型鏈)
function Father{
this.xxx= 80;
this.yyy= 100;
this.drink = function{}
}
Father.prototype.zzz= function{}
var father = new Father;
function Son{
this.aaa = 120;
this.singing = function{}
Father.call(this);
}
Son.prototype = new Father;
Son.prototype.constructor = Son;
var son = new Son
console.dir(son)
這麼寫有個不好的地方就是:子類私有的屬性中有父類私有的屬性,子類公有的屬性中也有父類私有的屬性; 根據我們前邊的知識,我們可以這麼來改寫
function Father{
this.xxx= 80;
this.yyy= 100;
this.drink = function{}
}
Father.prototype.zzz= function{}
var father = new Father;
function Son{
this.aaa = 120;
this.singing = function{}
Father.call(this);
}
Son.prototype.__proto__ = Father.prototype
var son = new Son
console.dir(son)
最後來一張思維導圖
如有錯誤,歡迎指正!


※一鍵幫你複製多個文件到多個機器——PowerShell小腳本
※「Spring」使用Spring和AMQP發送接收消息(下)
※Mina IoService介面定義及抽象實現
※vue-cli項目中怎麼mock數據
※Try My Best 儘力而為
TAG:達人科技 |
※Lua 面向對象
※Python3快速入門知識點:面向對象
※Perl 面向對象
※php對面向對象的支持,完全可以開發大型商城網站
※新iPhone全面曝光,將推兩款支持雙卡雙待的機型面向中國市場!
※Python入門基礎之面向對象四:運算符重載
※Spotify面向發展中國家推出低流量版音樂服務
※面向不同需求的對象存儲系統對比:Ceph與Swift
※Google面向入門用戶的Android Go,現在有一個好的開始
※面向對象:我想和你一起漫步在沙灘,在和煦的海風中感受春的氣息
※出門問問發布面向企業場景的智能交互屏TicKasa Show
※中國雙人滑面向社會公開選拔 下一對隋/韓在哪裡?
※面向對象:希望餘生都與您有關
※Niantic Labs推出面向開發者的全新AR多人實時競技平台
※Python指南:面向對象程序設計
※AppleCare+ for Mac正式面向中國市場推出
※谷歌推出兩款面向聽障人士的Android應用
※HTC Vive Focus將在今年內面向全球銷售
※我們面向的大海
※震驚!IBM將推出面向全商業的區塊鏈技術?