什么是面向?qū)ο? 程序中都是用對象結(jié)構(gòu)描述現(xiàn)實中一個具體事物
什么是對象: 程序中專門描述現(xiàn)實中一個具體事物的程序結(jié)構(gòu)
為什么: 現(xiàn)實中,一個數(shù)據(jù)态兴,必須屬于某個具體對象中,才有意義仔拟。
何時: 今后厨诸,只要描述一個事物,都要將事物的屬性和功能集中定義在一個對象中
如何: 面向?qū)ο笕筇攸c:
封裝蜜托,繼承,多態(tài)
封裝:
什么是: 創(chuàng)建一個對象霉赡,存儲一個事物的屬性和功能
其中: 事物的屬性橄务,會成為對象的屬性
屬性其實就是存在對象中的變量
事物的功能,會成為對象的方法
方法其實就是存在對象中的函數(shù)
功能和屬性穴亏,統(tǒng)稱為成員
為什么: 便于大量維護數(shù)據(jù)
何時: 只要使用面向?qū)ο蟮姆绞骄幊谭渑玻急仨毾葘⑹挛锏膶傩院凸δ芊庋b在對象中重挑,再按需使用對象的屬性和方法。
如何: 3種:
- 直接量:
var obj={
屬性名:值,
... : ... ,
方法名(){
... this.屬性名 ...
}
}
問題: 對象自己的方法棠涮,要使用自己的屬性值谬哀,缺找不到!
原因: 不加.訪問的變量严肪,只能在作用域鏈中查找史煎,無法自動進入對象中查找
解決: 錯誤: 在屬性前加"對象."
在對象內(nèi),禁止寫死對象名
因為對象名其實僅是一個普通變量名驳糯,很有可能發(fā)生變化
正確: 用this.屬性名:
this: 在函數(shù)執(zhí)行時篇梭,自動創(chuàng)建的一個關(guān)鍵詞
自動指向正在調(diào)用當(dāng)前函數(shù)的.前的對象
為什么: 不受對象名的影響
總結(jié): 今后,只要對象自己的方法酝枢,想訪問自己的屬性恬偷,必須用this.屬性名
var lilei=/*new */Object();
lilei.sname="Li Lei";
lilei.age=11;
lilei.intr=function(){
console.log(
"I'm "+this.sname
+", I'm "+this.age
);
}
console.dir(lilei);//顯示一個對象的存儲結(jié)構(gòu)
console.log(lilei.sname);
console.log(lilei.age);
lilei.intr();//this->lilei
lilei.age++;
console.log(lilei.age);
lilei.intr();
lilei.sname="Li Xiaolei";
lilei.intr();
- 用new: 2步:
- 先創(chuàng)建一個空對象
var obj=new Object(); //new可省略,()也可省略,但不能同時省 - 向空對象中添加新成員:
obj.屬性名=值;
obj.方法名=function(){ ... this.屬性名 ... }
說明: js中的對象,可隨時帘睦,通過強行賦值的方式袍患,添加新成員
何時: 如果在創(chuàng)建對象時,暫時不知道對象的成員
揭示: js中的對象竣付,底層其實就是關(guān)聯(lián)數(shù)組
相同: 1. 都可用.或[]隨時添加/訪問成員
2. 訪問不存在的成員诡延,不報錯,返回undefined
3. 都可用for in遍歷每個成員
不同: 對象比關(guān)聯(lián)數(shù)組用法簡單卑笨!
今后孕暇,都是用對象來代替關(guān)聯(lián)數(shù)組使用!
console.dir():xianshi
問題: 一次只能創(chuàng)建一個對象
如果反復(fù)創(chuàng)建相同結(jié)構(gòu)的多個對象赤兴,重復(fù)代碼會很多
解決:構(gòu)造函數(shù)
//DRY
//1. 定義構(gòu)造函數(shù)妖滔,描述學(xué)生類型的統(tǒng)一結(jié)構(gòu)
function Student(sname,age){
this.sname=sname;
this.age=age;
this.intr=function(){
console.log(
"I'm "+this.sname
+", I'm "+this.age);
}
}
//2. 用new調(diào)用構(gòu)造函數(shù)反復(fù)創(chuàng)建學(xué)生類型的具體對象
var lilei=new Student("Li Lei",11);
var hmm=new Student("Han Meimei",12);
console.dir(lilei);
console.dir(hmm);
lilei.intr();
hmm.intr();
- 用構(gòu)造函數(shù)(constructor):
什么是: 描述同一類型的多個對象,相同成員結(jié)構(gòu)的函數(shù)
第二個作用: 將一個空對象構(gòu)造為擁有屬性和功能的完整對象
何時: 只要反復(fù)創(chuàng)建同一類型的多個對象時桶良,都要先用構(gòu)造函數(shù)描述統(tǒng)一的結(jié)構(gòu)座舍,再用構(gòu)造函數(shù)創(chuàng)建對象
如何: 2步
1. 定義構(gòu)造函數(shù):
function 類型名(屬性參數(shù),....){
this.屬性名=屬性參數(shù);
... = ... ;
this.方法名=function(){
... this.屬性名 ...
}
}
2. 使用構(gòu)造函數(shù)反復(fù)創(chuàng)建對象:
var obj= new類型名(屬性值,...);
調(diào)用時的參數(shù)值,應(yīng)和定義構(gòu)造函數(shù)時的屬性參數(shù)保持一致陨帆。
new: 4件事:
1. 創(chuàng)建一個新的空對象
2. 自動讓新的子對象繼承構(gòu)造函數(shù)的原型對象
3. 調(diào)用構(gòu)造函數(shù)曲秉,將構(gòu)造函數(shù)中的this執(zhí)行正在創(chuàng)建的新對象。向新的空對象中強行添加新成員
4. 將新對象地址返回給變量保存
優(yōu): 重用結(jié)構(gòu)定義
缺: 浪費內(nèi)存
構(gòu)造函數(shù)ex:
function Student(sname,age){
this.sname=sname;
this.age=age;
this.intr=function(){
console.log("我是"+this.sname+",我今年"+this.age);
}
}
var lilei=new Student("Li lei","18");
console.log(lilei);
lilei.intr();
var Hanmeimei=new Student("Hanmeimei","21");
Hanmeimei.intr();
繼承:
什么是: 父對象的成員疲牵,子對象無需創(chuàng)建即可直接使用承二!
為什么: 代碼重用!節(jié)約內(nèi)存纲爸!
何時: 所有子對象都擁有相同的屬性值和方法定義時亥鸠,都要用繼承來實現(xiàn)
如何: js中所有繼承,都是繼承原型對象
什么是原型對象: 集中存儲所有子對象共有成員的父對象
為什么: 實現(xiàn)繼承
何時: 只要實現(xiàn)繼承,都要繼承原型對象
如何:
創(chuàng)建: 不用手動創(chuàng)建负蚊,買一贈一
其實創(chuàng)建構(gòu)造函數(shù)同時神妹,都附贈一個空的原型對象
繼承: 不用手動設(shè)置
用new創(chuàng)建新的子對象時,會自動設(shè)置新對象繼承構(gòu)造函數(shù)的原型對象
添加共有成員:
構(gòu)造函數(shù).prototype.成員=值;
總結(jié): 只要所有子對象共用的成員家妆,都必須集中存儲在原型對象中
自有屬性和共有屬性:
自有屬性: 直接保存在對象本地的屬性
共有屬性: 保存在原型對象中鸵荠,所有子對象共有的屬性
讀取: 兩者完全一樣: 對象.屬性名
修改: 自有屬性: 只能用子對象改: 子對象.自有屬性名=值
自有、共有屬性修改時的差別:I思S颊摇!
lilei.sname="li xiaolei"
Student.prototype.className="初二";
共有屬性: 只能用原型對象修改:
構(gòu)造函數(shù).prototype.共有屬性名=值
原型鏈: prototype chain
什么是: 由多級父對象塑荒,逐級繼承熄赡,形成的鏈式結(jié)構(gòu)
為什么: 為了更高級,更大范圍的重用
如何:
所有對象,都有__proto__屬性
原型對象的__proto__指向更上級的父對象
所有對象最終都繼承自O(shè)bject.prototype——頂級父對象
內(nèi)置對象的原型鏈:
其實每種內(nèi)置類型都有對應(yīng)的構(gòu)造函數(shù)和原型對象齿税,也最終都繼承自O(shè)bject.prototype
其中: 內(nèi)置類型的構(gòu)造函數(shù)負責(zé)創(chuàng)建該類型的子對象
內(nèi)置類型的原型對象負責(zé)保存該類型所有子對象共有的API
問題: 舊瀏覽器不支持新的API
解決: 向舊瀏覽器中的原型對象中手動添加一個函數(shù)
鄙視: 判斷一個對象是不是數(shù)組類型彼硫,有幾種方法:
typeof不行!
- 判斷原型對象:
Object.getPrototypeOf(obj)==Array.prototype
判斷obj是數(shù)組類型的子對象
問題: __proto__是內(nèi)部屬性凌箕,本不應(yīng)該被訪問到
解決: 用Object.getPrototypeOf(obj)
代替proto
- 判斷構(gòu)造函數(shù):
實例
obj instanceof Array
判斷obj是不是被構(gòu)造函數(shù)Array創(chuàng)造出來的
instanceof 不僅判斷直接父類型拧篮,而是所有在原型鏈上的類型,都返回true牵舱!
- 判斷對象的內(nèi)部class屬性
每個對象內(nèi)部串绩,都有一個隱藏的class屬性,記錄該對象創(chuàng)建時的數(shù)據(jù)類型
class屬性不會隨繼承關(guān)系的改變而改變
問題1: class是內(nèi)部屬性
解決: 只有最頂層的toString()才能輸出對象的class屬性值
[object class名]
問題2: 內(nèi)置類型的原型對象中幾乎都重寫了新的toString()
解決: 用call強行調(diào)用:
call: 讓一個對象芜壁,調(diào)用一個本來無法調(diào)用到的函數(shù)
何時: 只要希望調(diào)用一個本無法調(diào)用到的函數(shù)
如何: 要調(diào)用的函數(shù).call(對象)
Object.prototype.toString.call(obj)=="[object Array]"
說明obj的內(nèi)部屬性class的值為"Array"
- 多態(tài):
什么是: 同一個函數(shù)在不同情況下表現(xiàn)出不同的狀態(tài)
重寫: 如果子對象覺得父對象的成員不好用礁凡,可在本地定義同名成員,覆蓋父對象中繼承來的成員
為什么: 體現(xiàn)子對象和父對象之間的差異
何時: 只要子對象覺得父對象的成員不好用慧妄,就可以重寫顷牌!