js中的面向?qū)ο笕腴T
什么是對(duì)象
我們先來看高程三中是如何對(duì)對(duì)象進(jìn)行定義的
"無序?qū)傩缘募?,其屬性可以包括基本值、?duì)象或者函數(shù)",對(duì)象是一組沒有特定順序的的值。對(duì)象的沒個(gè)屬性或方法都有一個(gè)俄名字,每個(gè)名字都映射到一個(gè)值。
簡單來理解對(duì)象就是由屬性和方法來組成的
面向?qū)ο蟮奶攸c(diǎn)
封裝
對(duì)于一些功能相同或者相似的代碼,我們可以放到一個(gè)函數(shù)中去,多次用到此功能時(shí),我們只需要調(diào)用即可,無需多次重寫。
在這里我們可以理解為創(chuàng)造對(duì)象的幾種模式:單例模式,工廠模式,構(gòu)造函數(shù)模式,原型模式等。
繼承
子類可以繼承父類的屬性和方法
多態(tài)(重載和重寫)
- 重載:嚴(yán)格意義上說js中沒有重載的功能,不過我們可以通過判斷函數(shù)的參數(shù)的不同來實(shí)現(xiàn)不同的功能來模擬重載。
- 重寫:子類可以改寫父類的屬性和方法
javascript中的封裝
單例模式
小王在一個(gè)小公司,就自己一個(gè)前端,所以他寫js都是這樣的
var a = 1; function getNum(){ return 1; }
后來公司又招了個(gè)前端小明,于是變成他們2個(gè)一起寫同一個(gè)js了。一天小王發(fā)現(xiàn)自己寫的getNum方法出問題了,原來是小華寫的js中也有個(gè)getNum的函數(shù),代碼合并后把他的覆蓋掉了,于是便找小華理論去,經(jīng)過一番妥協(xié)后,兩人都把自己的代碼改了改
var xiaoming = { num:1, getNum:function(){ return 1; } } var xiaohua = { num:2, getNum: function(){ return 2; } }
這就是我們所謂的單例模式(命名空間)
我們把描述同一個(gè)事物的方法或者屬性放到同一個(gè)對(duì)象里,不同事物之間的方法或者屬性名相同相互也不會(huì)發(fā)生沖突。
單例模式的優(yōu)劣
1.使用單例模式,我們可以實(shí)現(xiàn)簡單的模塊化開發(fā)
var utils = { getCss:function(){ //code }, getByClass:function(){ //code }, setCss:function(){ //code } }
我們可以把自己寫好的工具方法放到一個(gè)單獨(dú)的js文件中,然后直接引入即可。
2.避免了全局變量名的沖突
需要注意的是,我們?cè)谝敫鱾€(gè)模塊的時(shí)候,需要注意引入的順序,引入順序是按照各模塊之間的相互依賴進(jìn)行前后排列的;
3.缺點(diǎn):
- 單例模式只是一定程度上避免了變量名的沖突,但并不能徹底解決此問題,而且在不同的對(duì)象下,我們可能會(huì)有很多功能相同的代碼,最終造成大量的冗余代碼。
- 單例模式讓每個(gè)對(duì)象有了自己獨(dú)立的命名空間,但是并不能批量生產(chǎn)的問題,每一個(gè)新的對(duì)象都要重新寫一份一模一樣的代碼。
var person1 = { name:'小明', age:24, showName:function(){ console.log('我的名字是:'+this.name) } }; var person1 = { name:'小華', age:25, showName:function(){ console.log('我的名字是:'+this.name) } };
工廠模式
1.工廠模式其實(shí)就是把需要一個(gè)個(gè)的編寫的對(duì)象,放在一個(gè)函數(shù)中統(tǒng)一的進(jìn)行創(chuàng)建,說白了就是普通函數(shù)的封裝。
2.工廠模式總共3步驟:
1)引進(jìn)原材料 --- 創(chuàng)建一個(gè)空對(duì)象
2)加工原材料 --- 加工對(duì)象:給對(duì)象添加屬性和方法;
3)輸出產(chǎn)品 --- 返回對(duì)象:return 對(duì)象;
function CreatePerson(name,age){ var obj={};//1.創(chuàng)建一個(gè)空對(duì)象 //2.加工對(duì)象 obj.name=name; obj.age=age; obj.showName=function(){ console.log('我的名字是:'+this.name) }; return obj;//3.輸出對(duì)象; } var person1 = CreatePerson('小明',23) var person2 = CreatePerson('小華',23) person1.showName(); //我的名字是:小明 person2.showName(); //我的名字是:小華
工廠模式的優(yōu)缺點(diǎn)
既然叫工廠模式,它就和我們周圍的工廠一樣,我們只需要把原材料放進(jìn)去,就能得到我們需要的產(chǎn)品了。
工廠模式也解決了單例模式的批量生產(chǎn)的問題,避免了單例模式中的大量冗余代碼,進(jìn)行系統(tǒng)的封裝,提高代碼的重復(fù)利用率
不過工廠模式跟我們js內(nèi)置類的調(diào)用方法不同
構(gòu)造函數(shù)模式
- 可以創(chuàng)建一個(gè)自定義的類,并且可以new出實(shí)例
- 構(gòu)造函數(shù)做的就是類和實(shí)例打交道。
//構(gòu)造函數(shù):首字母大寫(約定俗成); function CreatePerson(name,age){ //創(chuàng)建一個(gè)自定義的類 //構(gòu)造函數(shù)中的this,都是new出來的實(shí)例 //構(gòu)造函數(shù)中存放的都是私有的屬性和方法; this.name=name; this.age=age; this.showName=function(){ console.log('我的名字是:'+this.name) } } //實(shí)例1 var person1 = new CreatePerson('小明',25) //實(shí)例2 var person2 = new CreatePerson('小華',24)
這里說一下工廠模式和構(gòu)造函數(shù)模式的區(qū)別:
1. 在調(diào)用的時(shí)候不同:
工廠模式:調(diào)用的時(shí)候,只是普通函數(shù)的調(diào)用createPerson();
構(gòu)造函數(shù)模式:new CreatePerson();
2. 在函數(shù)體內(nèi)不同:
工廠模式有三步:1)創(chuàng)建對(duì)象 2)加工對(duì)象 3)返回對(duì)象;
構(gòu)造函數(shù)模式只有1步: 只有加工對(duì)象; 因?yàn)橄到y(tǒng)默認(rèn)會(huì)為其創(chuàng)建對(duì)象和返回對(duì)象;
3. 構(gòu)造函數(shù)默認(rèn)給我們返回了一個(gè)對(duì)象,如果我們非要自己手動(dòng)返回的話:
(1)手動(dòng)返回的是字符串類型:對(duì)以前實(shí)例上的屬性和方法沒有影響;
(2)手動(dòng)返回的是引用數(shù)據(jù)類型:以前實(shí)例身上的屬性和方法就被覆蓋了;實(shí)例無法調(diào)用屬性和方法;
構(gòu)造函數(shù)的方法都是私有方法,每個(gè)實(shí)例調(diào)用的都是自己私有的方法,同樣也會(huì)有許多重復(fù)的代碼。
我們可以使用原型模式來解決每個(gè)實(shí)例中都有相同方法的函數(shù)的問題
原型模式
function CreatePerson(name,age){ this.name=name; this.age=age; } // 我們把公有的方法放到函數(shù)的原型鏈上 CreatePerson.prototype.showName = function(){ console.log('我的名字是:'+this.name) } var person1 = new CreatePerson('小明',25) var person2 = new CreatePerson('小華',24) person1.showName() //小明
###### 原型模式的關(guān)鍵:
1)每個(gè)函數(shù)數(shù)據(jù)類型(普通函數(shù),類)上,都有一個(gè)屬性,叫prototype。
2)prototype這個(gè)對(duì)象上,天生自帶一個(gè)屬性,叫constructor:指向當(dāng)前這個(gè)類;
3)每個(gè)對(duì)象數(shù)據(jù)類型(普通對(duì)象,prototype,實(shí)例)上都有一個(gè)屬性,
叫做__proto__:指向當(dāng)前實(shí)例所屬類的原型;
這3句話理解了,下邊的東西就可以不用看了 //手動(dòng)滑稽
通過例子我們來看這幾句話是什么意思
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瀏覽器控制臺(tái)中顯示
從圖中可以看出,person1這個(gè)對(duì)象上有name和age兩個(gè)屬性,person1的__proto__指向了它的構(gòu)造函數(shù)(CreatePerson)的prototype上,而且還有一個(gè)showName的方法。
并且它們中有一條鏈關(guān)聯(lián)著: person1.__proto__ === CreatePerson.prototype
接著來看
function Foo(){ this.a=1; } Foo.prototype.a=2; Foo.prototype.b=3; var f1 = new Foo; //沒有參數(shù)的話括號(hào)可以省略 console.log(f1.a) //1 console.log(f1.b) // 3
以這個(gè)為例,當(dāng)我們查找f1.a時(shí),因?yàn)閒1中有這個(gè)屬性,所以我們得出 f1.a=1;當(dāng)我們查找f1.b時(shí),f1中沒有這個(gè)屬性,我們便順著f1.__proto__這條鏈去它的構(gòu)造器的prototype上找,所以我們得出了 f1.b = 3;
接著來說,F(xiàn)oo.prototype是個(gè)對(duì)象,那么它的__proto__指向哪里呢
還記的剛剛說的那句
每個(gè)對(duì)象數(shù)據(jù)類型(普通對(duì)象,prototype,實(shí)例)上都有一個(gè)屬性,叫做__proto__:指向當(dāng)前實(shí)例所屬類的原型
此外,我們應(yīng)該知道
每一個(gè)對(duì)象都是function Object這個(gè)構(gòu)造函數(shù)的實(shí)例
所以我們可以接著還原這個(gè)原型圖
等等,圖上貌似多了個(gè)個(gè)Object.prototype.__proto__ 指向了null,這是什么鬼?
我們這么來理解,Object.prototype是個(gè)對(duì)象,那么它的__proto__指向了它的構(gòu)造函數(shù)的prototype上,最后發(fā)現(xiàn)了還是指向它自身,這樣轉(zhuǎn)了個(gè)圈貌似是無意義的,于是便指向了null還沒完,我們發(fā)現(xiàn)對(duì)象都是函數(shù)(構(gòu)造器)創(chuàng)造出來的,那么函數(shù)是誰創(chuàng)造的呢?石頭里蹦出來的么?
在js中,function都是由function Function這個(gè)構(gòu)造器創(chuàng)造的,每一個(gè)函數(shù)都是Function的實(shí)例
現(xiàn)在基本上我們就能得出了完整的原型圖了
是不是有點(diǎn)亂?根據(jù)我們剛剛講的是能把這個(gè)圖理順的,這里需要注意下,F(xiàn)unction.__proto__是指向它的prototype的
多說一點(diǎn),判斷數(shù)據(jù)類型的方法時(shí),我們知道有個(gè)instanceof的方法
比如
A instanceof B
instanceof判斷的規(guī)則就是:
沿著A的__proto__這條線查找的同時(shí)沿著B的prototype這條線來找,如果兩條線能找到同一個(gè)引用(對(duì)象),那么就返回true。如果找到終點(diǎn)還未重合,則返回false。
再來看我們之前的那個(gè)例子
function Foo(){ this.a=1; } Foo.prototype.a=2; Foo.prototype.b=3; var f1 = new Foo; //沒有參數(shù)的話括號(hào)可以省略 console.log(f1.a) //1 console.log(f1.b) // 3
當(dāng)我們查找f1.a時(shí),因?yàn)閒1中有這個(gè)屬性,所以我們得出 f1.a=1;
當(dāng)我們查找f1.b時(shí),f1中沒有這個(gè)屬性,我們便順著f1.__proto__這條鏈去它的構(gòu)造器的prototype上找,所以我們得出了 f1.b = 3;
當(dāng)我們查找一個(gè)對(duì)象的屬性時(shí),先在這個(gè)對(duì)象的私有空間內(nèi)查找,如果沒找到,就順著對(duì)象的__proto__這條鏈去它的構(gòu)造器的ptototype上查找,如果還沒找到,接著沿__proto__向上查找,直到找到Object.prototype還沒有的話,這個(gè)值就為undefined,這就是所謂的原型鏈
列舉下網(wǎng)頁中的一些相關(guān)的原型鏈
有興趣的同學(xué)可自行通過瀏覽器控制臺(tái)看看我們常用的方法都是在哪個(gè)類上定義的,比如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)
這么寫有個(gè)不好的地方就是:子類私有的屬性中有父類私有的屬性,子類公有的屬性中也有父類私有的屬性;
根據(jù)我們前邊的知識(shí),我們可以這么來改寫
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); //利用call繼承了父類的私有屬性 } Son.prototype.__proto__ = Father.prototype var son = new Son console.dir(son)
最后來一張思維導(dǎo)圖
圖片如果放大也看不清的話 下載地址
以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持腳本之家!
- JS基于面向?qū)ο髮?shí)現(xiàn)的拖拽功能示例
- Javascript之面向?qū)ο?-封裝
- 歸納下js面向?qū)ο蟮膸追N常見寫法總結(jié)
- JavaScript面向?qū)ο缶帉戀徫镘嚬δ?/a>
- Javascript 面向?qū)ο螅ㄒ唬?共有方法,私有方法,特權(quán)方法)
- JS面向?qū)ο蠡A(chǔ)講解(工廠模式、構(gòu)造函數(shù)模式、原型模式、混合模式、動(dòng)態(tài)原型模式)
- JS 面向?qū)ο笾衿娴膒rototype
- 面向?qū)ο蟮腏avascript之二(接口實(shí)現(xiàn)介紹)
- JS面向?qū)ο缶幊讨畬?duì)象使用分析
- javascript面向?qū)ο笕腴T基礎(chǔ)詳細(xì)介紹
- javascript中的面向?qū)ο?/a>
相關(guān)文章
JavaScript使用高階生成器進(jìn)行過濾以生成素?cái)?shù)
生成器大家都知道是怎么一回事,但是高階生成器又是什么東西呢,下面小編就來為大家簡單介紹一下如何使用高階生成器進(jìn)行過濾以生成素?cái)?shù)吧2024-02-02js數(shù)組常用操作方法小結(jié)(增加,刪除,合并,分割等)
這篇文章主要介紹了js數(shù)組常用操作方法,結(jié)合實(shí)例總結(jié)了javascript數(shù)組的增加、刪除、合并、分割等操作技巧,需要的朋友可以參考下2016-08-08JavaScript數(shù)組常用方法解析及數(shù)組扁平化
這篇文章主要介紹了JavaScript數(shù)組常用方法解析及數(shù)組扁平化,數(shù)組作為在開發(fā)中常用的集合,除了for循環(huán)遍歷以外,還有很多內(nèi)置對(duì)象的方法,包括map,以及數(shù)組篩選元素filter等2022-07-07Three.js+React實(shí)現(xiàn)3D文字懸浮效果
這篇文章主要介紹了如何利用Three.js+React制作出神奇的3D文字懸浮效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以動(dòng)手嘗試一下2022-03-03Bootstrap學(xué)習(xí)筆記 輪播(Carousel)插件
Bootstrap 輪播(Carousel)插件是一種靈活的響應(yīng)式的向站點(diǎn)添加滑塊的方式。這篇文章主要介紹了Bootstrap學(xué)習(xí)筆記 輪播(Carousel)插件,需要的朋友可以參考下2017-03-03