面向對象編程
Paste_Image.png
一段完整的創建類的示例
// 如何創建一個類,包含有:靜態屬性方法,公有私有屬性方法?
var Book = (function(){
// 靜態私有變量
var bookNum = 0;
// 靜態私有方法
function checkName(name){}
var _book = function(id, newName, newPrice){
// 安全模式,防止未使用new操作符
if(this instanceof _book){
// 私有變量 方法
var name, price; function checkID(){}
// 共有屬性,方法
this.id = id;
this.getName = function(){ return name; };
this.getPrice = function(){ return price; };
this.setName = function(name){ name = name; };
this.setPrice = function(price){ price = price; };
console.log(++bookNum);
this.setName(newName);
this.setPrice(newPrice);
}
else{
return new _book(id, name, price);
}
};
_book.prototype = {
// 靜態公有屬性
isJSBook: false,
// 靜態共有方法
displayName: function(){
console.log(this.getName());
}
};
return _book;
}());
使用關閉包定義靜態私有變量與方法,所有實例創建過程中都能訪問到
Paste_Image.png
創建實例時,打印出累加之后的bookNum
當替換Book(即_book)的原型之后,之前創建的實例指向的原型并不會改變,之后在之后創建Book實例時運用新的原型
Paste_Image.png
觀察b3、b4的原型
當在原來的原型上變更之后,通過該原型創建的實例都能應用變更之后的原型
Paste_Image.png
這里定義重復了,原型上的getPrice方法將會被實例自身擁有的getPrice方法掩蓋住
繼承
- 方式一:類式繼承: 通過將子類的原型指定為父類的實例
function SuperClass(){
this.superValue = true;
}
SuperClass.prototype.getSuperValue = function(){
return this.superValue;
};
function SubClass(){
this.subValue = true;
}
SubClass.prototype = new SuperClass();
SubClass.prototype.getSubValue = function(){ return this.subValue;};
Paste_Image.png
缺點:
1、如果父類中存在引用類型屬性,則會被所有子類共用,一個子類修改之后將會影響到所有子類
2、無法在實例化時為父類傳遞初始化參數
- 方式二: 構造函數繼承: 在子類構造函數中通過call或者apply調用父類的構造函數,實現繼承父類定義的屬性方法
function SuperClass(id){
this.books = ['js', 'css', 'html'];
this.id = id;
}
SuperClass.prototype.showBooks = function(){
console.log(this.books.join());
};
function SubClass(id){
SuperClass.call(this, id);
}
Paste_Image.png
缺點:
1、子類沒有繼承父類的原型
2、每個實例化出來的子類對象都會單獨擁有一份父類上定義的屬性方法,無法復用父類的屬性或者方法
- 方式三: 組合繼承: 方式一與方式二的組合模式
function SuperClass(name){
this.name = name;
this.books = ['js', 'css','html'];
}
SuperClass.prototype.getName = function(){
console.log(this.name);
};
function SubClass(name, time){
SuperClass.call(this, name);
this.time = time;
}
SubClass.prototype = new SuperClass();
SubClass.prototype.getTime = function(){ console.log(this.time);}
Paste_Image.png
缺點:
1、父類構造函數執行了兩遍
2、子類實例化出來的對象原型中重復了一次父類構造函數中的屬性方法
- 方式四: 原型式繼承: 使用過渡函數作為構造函數,傳入的對象作為過渡函數的原型
function inheritObject(o){
function F(){}
F.prototype = o;
return new F();
}
缺點:
跟方式一有相同的缺點
- 方式五: 寄生式繼承: 在方式四的基礎上進行二次封
function createBook(obj){
var o = inheritObject(obj);
o.getName = function(){
console.log(this.name);
};
return o;
}
Paste_Image.png
- 方式六: 寄生組合式繼承: 寄生式繼承跟夠構造函數繼承的組合
function inheritPrototype(SubClass, SuperClass){
var p = inheritObject(SuperClass.prototype);
p.constructor = SubClass;
SubClass.prototype = p;
}
function SuperClass(name){
this.name = name;
this.books = ['js', 'css','html'];
}
SuperClass.prototype.getName = function(){
console.log(this.name);
};
function SubClass(name, time){
SuperClass.call(this, name);
this.time = time;
}
inheritPrototype(SubClass, SuperClass);
SubClass.prototype.getTime = function(){ console.log(this.time);
}
Paste_Image.png
子類添加原型方法只能在現有原型上一個添加
整個過程:先定義子類及父類與父類原型,然后子類原型引用父類的原型對象,然后子類在添加自己的原型方法,最后調用父類構造函數