面向?qū)ο蟮娜筇匦?/h4>
- 封裝: 在JS中使用對(duì)象封裝一些變量和函數(shù)
- 好處: 信息隱蔽, 方便擴(kuò)展維護(hù), 提高代碼的復(fù)用性
- 繼承: 一個(gè)類(對(duì)象)獲取另一個(gè)類(對(duì)象)的屬性和方法的一種形式
- 面向?qū)ο笳Z(yǔ)言定義: 是否有類的概念(c++ Java)
- JS沒有類的概念, JS從這個(gè)角度說不是面向?qū)ο笳Z(yǔ)言. 但面向?qū)ο缶哂欣^承特性, 可以說JS支持面向?qū)ο笳Z(yǔ)言
- 多態(tài): 同一操作, 作用于不同對(duì)象, 會(huì)產(chǎn)生不同行為(解釋)
- 實(shí)現(xiàn): JS天生就具有多態(tài)的特性(弱類型語(yǔ)言)
創(chuàng)建對(duì)象的方式
-
字面量的方式
var student = {
name: 'zs',
age: 16,
class: '一分鐘精通JS'
}
//一個(gè)班級(jí)有N個(gè)學(xué)生, 通過字面量形式, 需要?jiǎng)?chuàng)建N個(gè)學(xué)生對(duì)象
//問題: 創(chuàng)建多個(gè)同類型的對(duì)象時(shí), 大量代碼冗余(重復(fù)代碼)
//價(jià)值: 只需要?jiǎng)?chuàng)建簡(jiǎn)單的幾個(gè)對(duì)象
-
內(nèi)置的構(gòu)造函數(shù)
-
系統(tǒng)內(nèi)置的構(gòu)造函數(shù): Object | Array | Math | Date | Function | String | Number | Boolean
var stu = new Object();
stu.name= 'zs';
stu.age= 16;
stu.class= '一分鐘精通JS';
//跟字面量的方式差不多, 問題也是一樣-->創(chuàng)建對(duì)象的相同部分進(jìn)行函數(shù)封裝(簡(jiǎn)單工廠)
-
簡(jiǎn)單的工廠方式: 類似函數(shù)封裝, 相同的不變, 不同的作為參數(shù)傳進(jìn)來(lái)
function person(){
var stu = new Object();
stu.name= 'zs';
stu.age= 16;
stu.class= '一分鐘精通JS';
//返回該對(duì)象
return stu;
}
var stu1 = person();
var stu2 = person();
//問題: 兩個(gè)學(xué)生信息都一樣
//優(yōu)化如下: 不同的信息當(dāng)做參數(shù)傳進(jìn)來(lái)
function person(name, age, classes){
var stu = new Object();
stu.name= name;
stu.age= age;
stu.class= classes;
return stu;
}
function dog(name, age, classes){
var dog = new Object();
dog.name= name;
dog.age= age;
dog.class= classes;
return dog;
}
var stu3 = person('zs', 16, '一分鐘精通JS' );
var dog = dog('wangCai', 5 , '騎單車');
console.log(stu3 == dog); //false
//問題: 創(chuàng)建不同類型的對(duì)象時(shí), 無(wú)法分辨其類型
-
自定義構(gòu)造函數(shù)-參照上一章構(gòu)造函數(shù)創(chuàng)建對(duì)象
-
定義
- 自己定義的構(gòu)造函數(shù)(首字母大寫)-通過this設(shè)置屬性/方法-使用new調(diào)用構(gòu)造函數(shù)創(chuàng)建對(duì)象
-
執(zhí)行過程
- 通過new關(guān)鍵字調(diào)用構(gòu)造函數(shù),構(gòu)造函數(shù)內(nèi)部默認(rèn)創(chuàng)建一個(gè)新對(duì)象
- 將這個(gè)新對(duì)象賦值給this
- 通過this設(shè)置屬性和方法
- 默認(rèn)返回新創(chuàng)建對(duì)象
-
返回值
- 如果沒有顯示return, 默認(rèn)返回構(gòu)造函數(shù)內(nèi)部新創(chuàng)建的對(duì)象
- 若寫了返回值, 要看具體情況
- 如果返回值類型的數(shù)據(jù), 就直接忽略, 返回內(nèi)部新創(chuàng)建的對(duì)象
- 若返回引用類型的數(shù)據(jù), 直接返回該數(shù)據(jù)(會(huì)覆蓋內(nèi)部新創(chuàng)建的對(duì)象)
-
自定義構(gòu)造函數(shù)(區(qū)別于簡(jiǎn)單的工廠函數(shù))
- 函數(shù)名首字母大寫
- 自定義構(gòu)造函數(shù)內(nèi)部會(huì)默認(rèn)創(chuàng)建一個(gè)對(duì)象-默認(rèn)將這個(gè)對(duì)象賦值給this
- 默認(rèn)會(huì)返回新創(chuàng)建的對(duì)象
- 創(chuàng)建不同類型的對(duì)象時(shí), 可以分辨其類型
構(gòu)造函數(shù)注意事項(xiàng)
- 函數(shù)傳值: 函數(shù)當(dāng)做參數(shù)傳進(jìn)構(gòu)造函數(shù)
- 判斷對(duì)象的類型
-
對(duì)象 instanceof 構(gòu)造函數(shù): 判斷指定對(duì)象是否由某個(gè)構(gòu)造函數(shù)創(chuàng)建出來(lái)
- 獲取對(duì)象類型: 構(gòu)造器屬性
obj.constructor
- 構(gòu)造函數(shù)調(diào)用-區(qū)別于函數(shù)調(diào)用
new關(guān)鍵字: 默認(rèn)創(chuàng)建/返回對(duì)象
-
構(gòu)造函數(shù): 對(duì)這個(gè)對(duì)象進(jìn)行一些初始化的操作(將創(chuàng)建對(duì)象賦值給this, 通過this綁定屬性/方法)
function Person(name) {
// this = obj;
console.log(this);
this.name = name;
// return obj;
}
var p1 = new Person('zs');
// 構(gòu)造函數(shù)也是一個(gè)函數(shù)
var p2 = Person('ls'); // 可以這樣寫,但是不建議這樣做
console.log(p2); // undefined, 直接調(diào)用構(gòu)造函數(shù),this指向window
//分析打印結(jié)果
<script>
function fn(){
var t = 1;
this.x = 3;
document.write(t);
document.write(this.x);
}
var obj = new fn();
document.write(obj.x);
document.write(fn());
</script>
構(gòu)造函數(shù)的原型對(duì)象
-
原型對(duì)象定義
-
在構(gòu)造函數(shù)創(chuàng)建出來(lái)時(shí), 系統(tǒng)默認(rèn)會(huì)創(chuàng)建一個(gè)對(duì)象與這個(gè)構(gòu)造函數(shù)相關(guān)聯(lián), 這個(gè)對(duì)象稱為該構(gòu)造函數(shù)的原型對(duì)象
構(gòu)造函數(shù)的原型對(duì)象
-
作用
- 使用構(gòu)造函數(shù)創(chuàng)建出來(lái)的對(duì)象, 默認(rèn)就可以使用該構(gòu)造函數(shù)原型對(duì)象的屬性和方法
訪問原型對(duì)象: 構(gòu)造函數(shù).prototype
-
設(shè)置原型對(duì)象: 構(gòu)造函數(shù).prototype.name = 'name1';
- 原型對(duì)象本質(zhì)也是一個(gè)對(duì)象, 可以利用對(duì)象的動(dòng)態(tài)特性設(shè)置原型對(duì)象
-
約定
- 該對(duì)象構(gòu)造函數(shù)的原型對(duì)象
- 構(gòu)造函數(shù)的原型對(duì)象(原型) | 對(duì)象的原型對(duì)象(原型)
實(shí)例與實(shí)例化
- 實(shí)例: 通過構(gòu)造函數(shù)創(chuàng)建出來(lái)的對(duì)象.
- 一般說: XX是構(gòu)造函數(shù)的實(shí)例
- 實(shí)例成員: 實(shí)例屬性+實(shí)例方法
- 實(shí)例化: 通過構(gòu)造函數(shù)創(chuàng)建對(duì)象的過程
- 注意點(diǎn)
- 實(shí)例對(duì)象可以訪問實(shí)例成員和原型成員, 但是不能夠訪問靜態(tài)成員
- 構(gòu)造函數(shù)在訪問靜態(tài)方法時(shí), 內(nèi)部的this指向的是構(gòu)造函數(shù)自己, 不能訪問到實(shí)例對(duì)象的成員
function Person() {
this.name = "張三"; //實(shí)例屬性
var age = 18; //私有變量
this.showName = function () { //實(shí)例方法
console.log(this.name);
}
this.showAge = function () { //特權(quán)方法
console.log(age);
}
}
Person.prototype.show = function () { //原型方法
console.log(this.name);
}
Person.des = function () { //靜態(tài)方法
console.log(this.name);
}
var p1 = new Person();
p1.showName(); //張三
p1.showAge(); //18
p1.show(); //張三
//p1.des(); //undefined ? 報(bào)錯(cuò)(Y)
Person.des(); //undefined ? 報(bào)錯(cuò) ? 張三 ?Person(Y)
原型的使用方法
- 利用對(duì)象的動(dòng)態(tài)特性設(shè)置原型對(duì)象
- 提供一個(gè)構(gòu)造函數(shù)
- 設(shè)置原型對(duì)象的成員(原型屬性+原型方法)
- 添加成員:
構(gòu)造函數(shù).prototype.name = "name1";
- 修改成員:
構(gòu)造函數(shù).prototype.name = "name2";
- 刪除成員:
delete 構(gòu)造函數(shù).prototype.name;
- 替換原型對(duì)象: 自己定義的對(duì)象賦值給原型對(duì)象
- 替換原型對(duì)象之前創(chuàng)建的對(duì)象和替換之后創(chuàng)建的對(duì)象,他們的原型對(duì)象不是同一個(gè)對(duì)象
* 注意點(diǎn): 獲取替換原型對(duì)象的屬性與替換之前原型對(duì)象的屬性值不相等
* 建議: 最好在替換原型對(duì)象之后, 再創(chuàng)建對(duì)象
- 修正構(gòu)造器屬性
使用原型對(duì)象的注意事項(xiàng)
- 訪問原型對(duì)象的屬性-方式
-
對(duì)象.屬性(就近原則)
- 首先查找自身是否有該屬性, 若有就直接使用
- 若沒有就查找該對(duì)象原型對(duì)象的屬性, 若有就直接使用
- 再?zèng)]有就返回
undefined或報(bào)錯(cuò)
構(gòu)造函數(shù).prototype.屬性
- 設(shè)置原型對(duì)象
- 通過
對(duì)象.屬性設(shè)置屬性
- 如果有這個(gè)屬性就是修改, 沒有這個(gè)屬性就是添加屬性, 不會(huì)修改原型對(duì)象的屬性
- 設(shè)置原型對(duì)象的屬性
- 通過
構(gòu)造函數(shù).prototype.屬性或者替換原型
- 如果原型屬性是引用類型的數(shù)據(jù), 可以通過
對(duì)象.屬性.屬性的方式修改
構(gòu)造器屬性相關(guān)
-
constructor屬性: 指向與之對(duì)應(yīng)的構(gòu)造函數(shù)
-
對(duì)象.constructor: 訪問的是原型對(duì)象的constructor屬性
__proto__屬性
- 定義
- 構(gòu)造函數(shù)創(chuàng)建出來(lái)的對(duì)象, 默認(rèn)就有一個(gè)
__proto__屬性, 該屬性指向該對(duì)象對(duì)應(yīng)的構(gòu)造函數(shù)的原型對(duì)象
- 訪問原型對(duì)象-方式
構(gòu)造函數(shù).prototype
-
對(duì)象.__proto__
-
注意點(diǎn): 在正式開發(fā)中, 不建議使用. 該屬性不是ES標(biāo)準(zhǔn), 是部分瀏覽器廠商方便調(diào)試程序
__proto__和constructor結(jié)構(gòu)關(guān)系圖
hasOwnProperty()
- 語(yǔ)法:
對(duì)象.hasOwnProperty("屬性名")
- 定義: 判斷對(duì)象中是否存在指定的屬性(實(shí)例屬性)/ES5 中判斷對(duì)象的自有屬性(hasOwnProperty)
- 與
in區(qū)別: in判斷對(duì)象中是否存在指定的屬性(不區(qū)分實(shí)例屬性/原型屬性)
isPrototypeOf()
- 語(yǔ)法:
構(gòu)造函數(shù).protoType.isPrototypeOf(對(duì)象)
- 定義: 判斷一個(gè)對(duì)象是否是指定對(duì)象的原型對(duì)象(判斷原型對(duì)象是否在整條原型鏈上)
- 與
instanceof區(qū)別: instanceof判斷一個(gè)對(duì)象是否是指定構(gòu)造函數(shù)的實(shí)例對(duì)象
- 好處: 信息隱蔽, 方便擴(kuò)展維護(hù), 提高代碼的復(fù)用性
- 面向?qū)ο笳Z(yǔ)言定義: 是否有類的概念(c++ Java)
- JS沒有類的概念, JS從這個(gè)角度說不是面向?qū)ο笳Z(yǔ)言. 但面向?qū)ο缶哂欣^承特性, 可以說JS支持面向?qū)ο笳Z(yǔ)言
- 實(shí)現(xiàn): JS天生就具有多態(tài)的特性(弱類型語(yǔ)言)
字面量的方式
var student = {
name: 'zs',
age: 16,
class: '一分鐘精通JS'
}
//一個(gè)班級(jí)有N個(gè)學(xué)生, 通過字面量形式, 需要?jiǎng)?chuàng)建N個(gè)學(xué)生對(duì)象
//問題: 創(chuàng)建多個(gè)同類型的對(duì)象時(shí), 大量代碼冗余(重復(fù)代碼)
//價(jià)值: 只需要?jiǎng)?chuàng)建簡(jiǎn)單的幾個(gè)對(duì)象
內(nèi)置的構(gòu)造函數(shù)
-
系統(tǒng)內(nèi)置的構(gòu)造函數(shù): Object | Array | Math | Date | Function | String | Number | Boolean
var stu = new Object(); stu.name= 'zs'; stu.age= 16; stu.class= '一分鐘精通JS'; //跟字面量的方式差不多, 問題也是一樣-->創(chuàng)建對(duì)象的相同部分進(jìn)行函數(shù)封裝(簡(jiǎn)單工廠)
簡(jiǎn)單的工廠方式: 類似函數(shù)封裝, 相同的不變, 不同的作為參數(shù)傳進(jìn)來(lái)
function person(){
var stu = new Object();
stu.name= 'zs';
stu.age= 16;
stu.class= '一分鐘精通JS';
//返回該對(duì)象
return stu;
}
var stu1 = person();
var stu2 = person();
//問題: 兩個(gè)學(xué)生信息都一樣
//優(yōu)化如下: 不同的信息當(dāng)做參數(shù)傳進(jìn)來(lái)
function person(name, age, classes){
var stu = new Object();
stu.name= name;
stu.age= age;
stu.class= classes;
return stu;
}
function dog(name, age, classes){
var dog = new Object();
dog.name= name;
dog.age= age;
dog.class= classes;
return dog;
}
var stu3 = person('zs', 16, '一分鐘精通JS' );
var dog = dog('wangCai', 5 , '騎單車');
console.log(stu3 == dog); //false
//問題: 創(chuàng)建不同類型的對(duì)象時(shí), 無(wú)法分辨其類型
自定義構(gòu)造函數(shù)-參照上一章構(gòu)造函數(shù)創(chuàng)建對(duì)象
-
定義
- 自己定義的構(gòu)造函數(shù)(首字母大寫)-通過this設(shè)置屬性/方法-使用new調(diào)用構(gòu)造函數(shù)創(chuàng)建對(duì)象
-
執(zhí)行過程
- 通過new關(guān)鍵字調(diào)用構(gòu)造函數(shù),構(gòu)造函數(shù)內(nèi)部默認(rèn)創(chuàng)建一個(gè)新對(duì)象
- 將這個(gè)新對(duì)象賦值給this
- 通過this設(shè)置屬性和方法
- 默認(rèn)返回新創(chuàng)建對(duì)象
-
返回值
- 如果沒有顯示return, 默認(rèn)返回構(gòu)造函數(shù)內(nèi)部新創(chuàng)建的對(duì)象
- 若寫了返回值, 要看具體情況
- 如果返回值類型的數(shù)據(jù), 就直接忽略, 返回內(nèi)部新創(chuàng)建的對(duì)象
- 若返回引用類型的數(shù)據(jù), 直接返回該數(shù)據(jù)(會(huì)覆蓋內(nèi)部新創(chuàng)建的對(duì)象)
-
自定義構(gòu)造函數(shù)(區(qū)別于簡(jiǎn)單的工廠函數(shù))
- 函數(shù)名首字母大寫
- 自定義構(gòu)造函數(shù)內(nèi)部會(huì)默認(rèn)創(chuàng)建一個(gè)對(duì)象-默認(rèn)將這個(gè)對(duì)象賦值給this
- 默認(rèn)會(huì)返回新創(chuàng)建的對(duì)象
- 創(chuàng)建不同類型的對(duì)象時(shí), 可以分辨其類型
-
對(duì)象 instanceof 構(gòu)造函數(shù): 判斷指定對(duì)象是否由某個(gè)構(gòu)造函數(shù)創(chuàng)建出來(lái)
obj.constructor
new關(guān)鍵字: 默認(rèn)創(chuàng)建/返回對(duì)象-
構(gòu)造函數(shù): 對(duì)這個(gè)對(duì)象進(jìn)行一些初始化的操作(將創(chuàng)建對(duì)象賦值給this, 通過this綁定屬性/方法)
function Person(name) { // this = obj; console.log(this); this.name = name; // return obj; } var p1 = new Person('zs'); // 構(gòu)造函數(shù)也是一個(gè)函數(shù) var p2 = Person('ls'); // 可以這樣寫,但是不建議這樣做 console.log(p2); // undefined, 直接調(diào)用構(gòu)造函數(shù),this指向window //分析打印結(jié)果 <script> function fn(){ var t = 1; this.x = 3; document.write(t); document.write(this.x); } var obj = new fn(); document.write(obj.x); document.write(fn()); </script>
原型對(duì)象定義
-
在構(gòu)造函數(shù)創(chuàng)建出來(lái)時(shí), 系統(tǒng)默認(rèn)會(huì)創(chuàng)建一個(gè)對(duì)象與這個(gè)構(gòu)造函數(shù)相關(guān)聯(lián), 這個(gè)對(duì)象稱為該構(gòu)造函數(shù)的原型對(duì)象
構(gòu)造函數(shù)的原型對(duì)象
作用
- 使用構(gòu)造函數(shù)創(chuàng)建出來(lái)的對(duì)象, 默認(rèn)就可以使用該構(gòu)造函數(shù)原型對(duì)象的屬性和方法
訪問原型對(duì)象: 構(gòu)造函數(shù).prototype
設(shè)置原型對(duì)象: 構(gòu)造函數(shù).prototype.name = 'name1';
- 原型對(duì)象本質(zhì)也是一個(gè)對(duì)象, 可以利用對(duì)象的動(dòng)態(tài)特性設(shè)置原型對(duì)象
約定
- 該對(duì)象構(gòu)造函數(shù)的原型對(duì)象
- 構(gòu)造函數(shù)的原型對(duì)象(原型) | 對(duì)象的原型對(duì)象(原型)
- 一般說: XX是構(gòu)造函數(shù)的實(shí)例
- 實(shí)例成員: 實(shí)例屬性+實(shí)例方法
- 實(shí)例對(duì)象可以訪問實(shí)例成員和原型成員, 但是不能夠訪問靜態(tài)成員
- 構(gòu)造函數(shù)在訪問靜態(tài)方法時(shí), 內(nèi)部的this指向的是構(gòu)造函數(shù)自己, 不能訪問到實(shí)例對(duì)象的成員
function Person() {
this.name = "張三"; //實(shí)例屬性
var age = 18; //私有變量
this.showName = function () { //實(shí)例方法
console.log(this.name);
}
this.showAge = function () { //特權(quán)方法
console.log(age);
}
}
Person.prototype.show = function () { //原型方法
console.log(this.name);
}
Person.des = function () { //靜態(tài)方法
console.log(this.name);
}
var p1 = new Person();
p1.showName(); //張三
p1.showAge(); //18
p1.show(); //張三
//p1.des(); //undefined ? 報(bào)錯(cuò)(Y)
Person.des(); //undefined ? 報(bào)錯(cuò) ? 張三 ?Person(Y)
- 提供一個(gè)構(gòu)造函數(shù)
- 設(shè)置原型對(duì)象的成員(原型屬性+原型方法)
- 添加成員:
構(gòu)造函數(shù).prototype.name = "name1"; - 修改成員:
構(gòu)造函數(shù).prototype.name = "name2"; - 刪除成員:
delete 構(gòu)造函數(shù).prototype.name;
- 添加成員:
- 替換原型對(duì)象之前創(chuàng)建的對(duì)象和替換之后創(chuàng)建的對(duì)象,他們的原型對(duì)象不是同一個(gè)對(duì)象
* 注意點(diǎn): 獲取替換原型對(duì)象的屬性與替換之前原型對(duì)象的屬性值不相等
* 建議: 最好在替換原型對(duì)象之后, 再創(chuàng)建對(duì)象
- 修正構(gòu)造器屬性
-
對(duì)象.屬性(就近原則)- 首先查找自身是否有該屬性, 若有就直接使用
- 若沒有就查找該對(duì)象原型對(duì)象的屬性, 若有就直接使用
- 再?zèng)]有就返回
undefined或報(bào)錯(cuò)
構(gòu)造函數(shù).prototype.屬性
- 通過
對(duì)象.屬性設(shè)置屬性- 如果有這個(gè)屬性就是修改, 沒有這個(gè)屬性就是添加屬性, 不會(huì)修改原型對(duì)象的屬性
- 設(shè)置原型對(duì)象的屬性
- 通過
構(gòu)造函數(shù).prototype.屬性或者替換原型 - 如果原型屬性是引用類型的數(shù)據(jù), 可以通過
對(duì)象.屬性.屬性的方式修改
- 通過
constructor屬性: 指向與之對(duì)應(yīng)的構(gòu)造函數(shù)對(duì)象.constructor: 訪問的是原型對(duì)象的constructor屬性__proto__屬性- 構(gòu)造函數(shù)創(chuàng)建出來(lái)的對(duì)象, 默認(rèn)就有一個(gè)
__proto__屬性, 該屬性指向該對(duì)象對(duì)應(yīng)的構(gòu)造函數(shù)的原型對(duì)象
構(gòu)造函數(shù).prototype-
對(duì)象.__proto__-
注意點(diǎn): 在正式開發(fā)中, 不建議使用. 該屬性不是ES標(biāo)準(zhǔn), 是部分瀏覽器廠商方便調(diào)試程序
__proto__和constructor結(jié)構(gòu)關(guān)系圖
-
對(duì)象.hasOwnProperty("屬性名")
in區(qū)別: in判斷對(duì)象中是否存在指定的屬性(不區(qū)分實(shí)例屬性/原型屬性)構(gòu)造函數(shù).protoType.isPrototypeOf(對(duì)象)
instanceof區(qū)別: instanceof判斷一個(gè)對(duì)象是否是指定構(gòu)造函數(shù)的實(shí)例對(duì)象
