面向對象編程
1、封裝
- 函數類
var Book = function(id,bookname,price){
this.id = id
this.bookname = bookname
this.price = price
}
- 類的原型
1)爲原型對象屬性賦值
Book.prototype.display = function(){}
2)將對象賦值給類的原型對象
Book.prototype = {
display: function(){}
}
以上兩者區別:
通過this添加屬性、方法 | 通過prototype繼承屬性、方法 |
---|---|
該對象獨有的屬性和方法,再創建新對象時,需要重新創建屬性和方法 | 創建新對象無需重複創建屬性和方法 |
在當前對象上添加的 | 添加到prototype中 |
2、屬性和方法的封裝:
js實現方式:
- this 創建的屬性------->訪問對象共有屬性和對象共有方法
- this創建的方法(特權方法)-------->(1)訪問對象共有屬性和對象共有方法 (2)訪問類或對象自身的私有屬性和私有方法
// 私有屬性和私有方法,特權方法,對象共有屬性和對象共有方法,構造器
var Book = function(id, bookname, price){
var num = 1 // 私有屬性
// 私有方法
function checkId(){
}
// 特權方法
this.getName = function(){}
this.getPrice = function(){}
this.setName = function(){}
this.setPrice = function(){}
// 對象共有屬性
this.id = id
// 對象共有方法
this.copy = function(){}
// 構造器
this.setName(name)
this.setPrice(price)
}
- 類外面通過點語法添加的屬性和方法---------->類的靜態共有屬性和類的靜態共有方法 (對象不能訪問)
- 類通過prototype創建的屬性和方法------------>共有屬性和共有方法(因爲可以被this訪問到)
// 類靜態共有屬性
Book.isChinese = true
// 類靜態共有方法
Book.resetTime = function()[]
Book.prototype = {
// 共有屬性
isJSBook: false,
// 共有方法
display: function(){}
}
var b = new Book(11,'lala',50)
console.log(b.num) // undefined
console.log(b.isJsBook) // false
console.log(b.id) // 11
console.log(b.isChinese) // undefined
3、閉包實現:
有時將類的靜態變量通過閉包來實現
var Book = (function(){
var num = 1 // 靜態私有屬性
// 靜態私有方法
function checkId(){
}
return function(newId, newName, newPrice){
// 私有變量
var name,price
// 私有方法
function checkId(){}
// 特權方法
this.getName = function(){}
this.getPrice = function(){}
this.setName = function(){}
this.setPrice = function(){}
// 對象共有屬性
this.id = id
// 對象共有方法
this.copy = function(){}
// 構造器
this.setName(name)
this.setPrice(price)
}
// 構造原型
_book.prototype = {
// 靜態共有屬性
isJsBook: false;
// 靜態共有方法
display: function(){}
}
// 返回類
return _book
})();
4、小結:
2、繼承
1、類式繼承
// 聲明父類
function Book () {
this.name = '計算機'
}
// 爲父類添加方法
Book.prototype.getName = function () {
return this.name
}
// 聲明子類
function pattern() {
this.patternCom = '設計模式'
}
// 繼承父類
pattern.prototype = new Book()
//爲子類添加方法
pattern.prototype.getPattern = function () {
return this.patternCom
}
- 原理
類式繼承缺點:
(1)因爲子類是通過其prototype對父類進行實例化繼承父類,若父類中的共有屬性是引用類型的話,就會在子類中被所有實例共用。因此在子類實例中更改從父類繼承過來的共有屬性會影響到其他子類。
(2)無法向父類傳遞參數,因而也無法在實例化父類時對構造函數內屬性進行初始化。
2、構造函數繼承
// 聲明父類
function Book (id) {
this.name = '計算機'
this.id = id
}
// 爲父類添加方法
Book.prototype.getName = function () {
return this.name
}
// 聲明子類
function pattern(id) {
Book.call(this,id)
}
call()可以更改函數的作用環境,使子類變量在父類中執行一遍,可以繼承父類的共有屬性。
- 不足
由於該繼承沒有涉及prototype,所以不能繼承父類中的原型方法。如果必須要繼承,就需要放在構造函數中,這樣實例之間不能共用,造成代碼重複。
3、組合繼承
- 原理
- 不足
父類構造函數調用了2遍。
第一次:構造函數繼承時執行了一遍父類構造函數
第二次:實現子類繼承時,調用了父類構造函數
4、原型式繼承
// 聲明父類
function Book (id) {
// 聲明一個過渡函數對象
function pattern() {}
// 過渡對象的原型繼承父類對象
pattern.prototype = id
// 返回過渡對象的實例,該實例原型繼承了父對象
return new pattern()
}
5、寄生式繼承
/ 聲明父類
function Book (id) {
// 聲明一個過渡函數對象
function pattern() {}
// 過渡對象的原型繼承父類對象
pattern.prototype = id
// 返回過渡對象的實例,該實例原型繼承了父對象
return new pattern()
}
var book = {
name: '123'
}
function createBook(obj) {
// 通過原型繼承方式創建新對象
var o = new Book(obj)
// 拓展新對象
o.getName = function(){}
// 返回拓展後的新對象
return o
}
寄生式繼承就是對原型繼承的第二次封裝,並在第二次封裝是對繼承的對象進行了拓展,這樣新創建的對象中不僅有父類的屬性和方法還有新創建的屬性和方法。
6、寄生組合式繼承
// 聲明父類
function inheritobject (id) {
// 聲明一個過渡函數對象
function pattern() {}
// 過渡對象的原型繼承父類對象
pattern.prototype = id
// 返回過渡對象的實例,該實例原型繼承了父對象
return new pattern()
}
/*
* subclass: 子類 superclass: 父類
* */
function inheritprototype(subclass, superclass) {
// 緩存父類原型
var p = inheritobject(subclass.prototype)
// 修正子類的constructor
p.constructor = subclass
// 設置子類的原型
subclass.prototype = p
}
- 原理
3、多態
- 概念
同一種方法多種調用方式。通過對傳遞的參數判斷來決定執行邏輯,即可實現一種多態處理機制。