單例模式
單例模式:
是一種項目開發中經常使用的模式,因為項目中我們可以使用單例模式來進行我們的"模塊開發"
"模塊化開發":
對於一個相對來說比較大的項目,需要多人協作的開發,我們一般情況下會根據當前項目的需求划分為幾個功能板塊,每個人負責一部分,同時開發,最后把每個人的代碼進行合並
比如:
- 公共模塊
var utils = {
select: function(){
}
}
- 頁卡模塊中的change->實現選項卡切換
var tabRender = {
change: function(){
utils.select(); // 在自己的名命空間下調用其他名命空間的方法
}
}
+搜索模塊change->搜索內容變化處理的
var searchRender = {
change: function (){
this..clickEven(); // 在自己的名命空間下調用自己名命空間的方法
}
clickEvent: function(){
}
}
工廠模式
單例模式雖然解決了分組的作用,但是不能實現批量的生產,屬於手工作業模式
函數的封裝:
把實現同一件事情的相同的代碼放到一個函數中,以后如果在想實現這個功能,不需要從新的編寫這些代碼了,只需要執行當前的函數即可
低耦合高內聚:
減少頁面中冗余代碼,提高代碼的重復利用率
function createJsPerson(name, age){
var obj = {};
obj.name = name;
obj.age = age;
obj.writeJS = function(){
console.log("my name is " + this.name + ", i can write js ~~")
}
return obj;
}
var p1 = createJsPerson("lemon1", 21)
var p2 = createJsPerson("lemon2", 22)
js中不存在重載,方法名一樣的話,后面的會把前面的覆蓋掉,最后只保留一個
function sum(num){
if(typeof num === "undefined"){
return 0;
}
return num;
}
sum(100);
sum(0)
構造函數模式
構造函數模式的目的就是為了創建一個自定義類,並且創建這個類的實例
function CreateJsPerson(name, age){
this.name = name;
this.age = age;
this.writeJS = function(){
console.log("my name is " + this.name + ", i can write js ~~")
}
}
var p1 = new CreateJsPerson("lemon1", 21)
var p2 = new CreateJsPerson("lemon2", 22)
構造函數和工廠模式的區別
執行的時候
- 普通函數執行->createJsPerson()
- 構造函數模式->new CreateJsPerson(), 通過new執行后,createJsPerson就是一個類了,而函數執行的返回值(p1)就是CreateJsPerson這個類的一個實例)
在函數代碼執行的時候
- 相同:都是形成一個私有的作用域,然后形參賦值->解釋->代碼從上到下執行
- 不同:在代碼執行之前,不用自己手動創建對象了,瀏覽器會默認創建一個對象的數據類型的值,這個對象其實就是我們當前類的一個實例
接下來,代碼從上到下執行,以當前的實例為執行的主體,this代表的就是當前的實例
最后瀏覽器會默認的把創建的實例返回
JS中所有的類都是函數數據類型的,它通過new執行變成了一個類,但是它本身也是一個普通的函數
JS中所有的實例都死對象數據類型的
p1和p2都是CreateJsPerson這個類的實例,所以都擁有writeJs這個方法,但是不同實例之間的方法是不一樣的
在類中給實例增加的屬性(this.xxx = xxx)屬於當前實例的私有的屬性,實例和實例之間單獨的個體,所以私有的屬性之間是不相等的
console.log(p1.writeJs === p2.writeJs);
->false
this問題
var name = ""
var res = CreateJsPerson('-lemon', -22);
console.log(name);
console.log(age)
-> '-lemon'
-> -22
這樣寫不是構造函數模式執行而是普通的函數執行,由於沒有寫return所以res = undefined, 並且CreateJsPerson這個方法中的this是window
構造函數模式(擴展)
function Fn(){
this.x = 100;
this.getX = function(){
console.log(this.x)
}
}
var f1 = new Fn;
f1.getX(); // 方法中的this是f1 100
var ss = f1.getX;
ss(); // 方法中的this是window undefined
- 在構造函數模式中new Fn()執行, 如果Fn不需要傳遞參數的話, 后面的小括號可以省略
- this的問題:在類中出現的this.xxx = xxx 中的this都是當前類的實例,而某一個屬性值(方法),方法中的this需要看方法執行的時候,前面是否有"."才能知道this是誰
- 類有普通函數的一面,當函數執行的時候, var num其實只是當前形成的私有作用域中的私有變量而已, 它和f1這個實例沒有任何關系.只有this.xxx = xxx才相當於給f1這個實例增加私有的屬性和方法,才和我們的f1有關系
function Fn(){
var num = 10;
this.x = 100;
this.getX = function(){
console.log(this.x)
}
}
var f1 = new Fn;
console.log(f1.num); // -> undefined
- 在構造函數模式中,瀏覽器會默認的把我們的實例返回(返回的是一個對象數據類型的值),如果我們自己手動寫了return返回:
返回的是一個基本數據類型的值,當前實例是不變的,例如: return 100;
返回的是一個引用數據類型的值,當前的實例會被自己返回的值替換掉,例如: return {name: 'lemon'}, 我們的f1就不在是Fn的實例了,而是對象 {name: 'lemon'}
function Fn(){
var num = 10;
this.x = 100;
this.getX = function(){
console.log(this.x)
}
return {name: 'lemon', age: 22};
}
var f1 = new Fn;
console.log(f1); // {name: 'lemon', age: 22}
function Fn(){
var num = 10;
this.x = 100;
this.getX = function(){
console.log(this.x)
}
return 100;
}
var f1 = new Fn;
console.log(f1); // 不變
檢測屬性
- 檢測某一個實例是否屬於這個類
console.log(f1 instanceof Fn); // -> true
console.log(f1 instanceof Array); // -> true
- f1和f2都是Fn這個類的一個實例,都擁有x和getX兩個屬性,但是這兩個屬性都是各自都屬性,所以
console.log(f1.getX === f2.getX); // -> false
- in 檢測某一個屬性是否屬於這個對象(attr in object), 不管是私有的屬性還是公有的屬性, 只要存在, 用in來檢測都是true
console.log("getX" in f1); // -> true
- hasOwnProperty: 用來檢測某一個屬性是否為這個對象的"私有屬性",這個方法只能檢測私有的屬性
console.log(f1.hasOwnProperty("getX")); // -> true
- isPrototypeOf: 用來判斷指定對象object1是否存在於另一個對象object2的原型鏈中,是則返回true,否則返回false
object1.isPrototypeOf(object2);
如果object2的原型鏈中包含object1,那么isPrototypeOf方法返回true
如果object2不是一個對象或者object1沒有出現在object2中的原型鏈中,isPrototypeOf方法將返回false.