為什么有設(shè)計(jì)模式的概念?
1.設(shè)計(jì)模式是代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)套么,為了可重用代碼岖是,保證代碼的可靠性等.
2.設(shè)計(jì)模式主要分為三大類(lèi)型:創(chuàng)建型模式棉圈,結(jié)構(gòu)型模式和行為型模式.
1.單例模式
- 定義:
- 單件模式確保一個(gè)類(lèi)只有一個(gè)實(shí)例,并提供一個(gè)全局訪問(wèn)點(diǎn).
- 使用場(chǎng)景:
- 用于創(chuàng)建獨(dú)一無(wú)二的碰凶,只能有一個(gè)實(shí)例的對(duì)象,單件模式給了我們一個(gè)全局的訪問(wèn)點(diǎn)鹿驼,和全局變量一樣方便又沒(méi)有全局變量的缺點(diǎn).
- 把全局變量當(dāng)成
單例
來(lái)使用容易造成命名污染.
防止命名空間污染的方法:
- 使用命名空間
- 使用閉包封裝私有變量
<script type="text/javascript">
var People = (function () {//var的函數(shù)方法所以用大寫(xiě)
var instance;
function init() {
//定義私有方法和屬性
//做某事
return {
//定義公共方法和屬性
};
}
return {
createPeople: function () {
if (!instance) {//只能有一份內(nèi)存的對(duì)象,有就不創(chuàng)建,沒(méi)就創(chuàng)建
instance = init();
}
return instance;
}
};
}());
var obj1 = People.createPeople();
var obj2 = People.createPeople();
</script>
2.構(gòu)造函數(shù)模式
- 組件,封裝,復(fù)雜.
- JavaScript里函數(shù)有個(gè)原型屬性叫prototype欲低,當(dāng)調(diào)用構(gòu)造函數(shù)創(chuàng)建對(duì)象的時(shí)候,所有該構(gòu)造函數(shù)原型的屬性在新創(chuàng)建對(duì)象上都可用
- 構(gòu)造函數(shù)用于創(chuàng)建特定類(lèi)型的對(duì)象,不僅聲明了使用的對(duì)象畜晰,構(gòu)造函數(shù)還可以接受參數(shù)砾莱。
- 你可以自定義自己的構(gòu)造函數(shù),然后在里面聲明自定義類(lèi)型對(duì)象的屬性或方法.
<script type="text/javascript">
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayName = function () {
return this.name;
};
var student = new Person('tony', 20);
console.log(student);
</script>
3.混合模式
- 為什么使用混合模式實(shí)現(xiàn)繼承?
實(shí)現(xiàn)對(duì)象的繼承,我們可以通過(guò)對(duì)象冒充,也可以通過(guò)原型鏈的方式.
但是,對(duì)象冒充就要求必須使用構(gòu)造函數(shù)方式,而原型鏈則無(wú)法使用構(gòu)造函數(shù),那么,我們就綜合一下,采區(qū)混合模式來(lái)實(shí)現(xiàn)繼承.
- 創(chuàng)建類(lèi)的最好方式,是用構(gòu)造函數(shù)定義屬性,使用原型方式定義方法.這樣的機(jī)制同樣適用于繼承機(jī)制,用對(duì)象冒充來(lái)繼承構(gòu)造函數(shù)的屬性,用原型鏈繼承prototype對(duì)象的方法
<script type="text/javascript">
var Person = function (name, age) {
this.name = name;
this.age = age;
};
Person.prototype.sayName = function () {
console.log(this.name);
}
var Student = function (name, age, score) {
//這里的 call作用:改變作用域,可以引用構(gòu)造函數(shù)
Person.call(this, name, age);//this是student
this.score = score;
//student繼承了person的屬性
};
//Object.create()可以調(diào)用這個(gè)方法來(lái)創(chuàng)建一個(gè)新對(duì)象凄鼻。
//新對(duì)象的原型就是調(diào)用 create方法時(shí)傳入的第一個(gè)參數(shù)
Student.prototype = Object.create(Person.prototype);
//student繼承了person的方法
// Student.prototype = create(Person.prototype);
// function create (parentObj){
// function F(){}
// F.prototype = parentObj;
// return new F();
// };//這一段等同于上面Object.create.(Person.prototype).
Student.prototype.sayScore = function () {
console.log(this.score);
}
var student = new Student("likefool", 18, 90);
console.log(student);//obj{屬性+方法}
student.sayName();//'likefool'
//student繼承了person的屬性和方法
//混合模式= 構(gòu)造函數(shù)模式 + call繼承屬性
</script>
4.工廠模式
- 使用場(chǎng)景
- 創(chuàng)建新對(duì)象腊瑟,且該對(duì)象需要被被封裝.
工廠模式通過(guò)讓子類(lèi)來(lái)決定該創(chuàng)建的對(duì)象是什么,來(lái)達(dá)到將對(duì)象創(chuàng)建的過(guò)程封裝的目的.
創(chuàng)建對(duì)象的方法使用的是繼承块蚌,用于創(chuàng)建一個(gè)產(chǎn)品的實(shí)例.
<script type="text/javascript">
function createPerson(opts) {
var person = {
name: opys.name || 'peter'
};
person.sayName = function () {
console.log(this.name);
}
return person;
}
var p1 = createPerson({ name: 'tom' });
var p2 = createPerson({ name: 'kite' })
</script>
5.模塊模式
- 立即執(zhí)行函數(shù),直接return結(jié)果供外部使用,不污染全局變量
<script type="text/javascript">
var Person = (function(){
var name = 'ruoyu';
function sayName(){
console.log(name);
}
return {
name: name,
sayName: sayName
}
})()
Person.sayName();
</script>
6.發(fā)布訂閱模式(即觀察者模式)
- 觀察者模式又叫發(fā)布訂閱模式闰非,它定義了一種
一對(duì)多
的關(guān)系盏袄,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽(tīng)某一個(gè)主題對(duì)象
彩匕,這個(gè)主題對(duì)象的狀態(tài)發(fā)生變化時(shí)就會(huì)通知所有的觀察者對(duì)象,使得它們能夠自動(dòng)更新自己扬卷。
- 使用觀察者模式的好處:
支持簡(jiǎn)單的廣播通信纱控,自動(dòng)通知所有已經(jīng)訂閱過(guò)的對(duì)象辆毡。
頁(yè)面載入后目標(biāo)對(duì)象很容易與觀察者存在一種動(dòng)態(tài)關(guān)聯(lián)菜秦,增加了靈活性。
- 觀察者主要讓訂閱者與發(fā)布者
解耦
胚迫,發(fā)布者不需要知道哪些模塊訂閱了這個(gè)主題喷户,它只管發(fā)布這個(gè)主題就可以了,同樣訂閱者也無(wú)需知道那個(gè)模塊會(huì)發(fā)布這個(gè)主題访锻,它只管訂閱這個(gè)主題就可以了
<script type="text/javascript">
var EventCenter = (function () {
var events = {};
/*
{
my_event: [{handler: function(data){xxx}}, {handler: function(data){yyy}}]
}
*/
//上面用數(shù)組保存方法的原因:這樣實(shí)現(xiàn)了一個(gè)fire調(diào)用多個(gè)方法.一對(duì)多.
function on(evt, handler) {
events[evt] = events[evt] || [];
events[evt].push({
handler: handler
});
}
function fire(evt, args) {
if (!events[evt]) {
return;
}
for (var i = 0; i < events[evt].length; i++) {
events[evt][i].handler(args);
}
}
return {
on: on,
fire: fire
}
})();
EventCenter.on('my_event', function (data) {
console.log('my_event received...');
});
EventCenter.on('my_event', function (data) {
console.log('my_event2 received...');
});
EventCenter.fire('my_event',);
//邏輯:
//最外面放一個(gè)空對(duì)象.
//A方法作用:講若干函數(shù)放入數(shù)組
//B方法:調(diào)用A里面所有的方法.
//AB怎么聯(lián)系起來(lái):通過(guò)外面的events對(duì)象,AB都是操作events對(duì)象.
//所以1對(duì)多.
</script>
參考:
7.發(fā)布訂閱模式的范例
<script type="text/javascript">
var EventCenter = (function () {
//外部創(chuàng)建一個(gè)可以包含數(shù)組的對(duì)象
var events = {};
/*
{
my_event: [{handler: function(data){xxx}}, {handler: function(data){yyy}}]
}
*/
//這里只保存方法到數(shù)組,不做操作.
function on(evt, handler) {
events[evt] = events[evt] || [];
events[evt].push({
handler: handler
});
}
//對(duì)上面保存在數(shù)組里的函數(shù)做相關(guān)操作
//重點(diǎn)是:都是對(duì)同一event對(duì)象的數(shù)組操作
function fire(evt, args) {
if (!events[evt]) {
return;
}
for (var i = 0; i < events[evt].length; i++) {
events[evt][i].handler(args);
}
}
function off(evt) {
delete events[evt]
}
return {
on: on,
fire: fire,
off: off
}
})();
EventCenter.on('my_event', function (data) {
console.log('my_event received...');
});
EventCenter.on('my_event', function (data) {
console.log('my_event2 received...');
});
EventCenter.fire('my_event');
EventCenter.on('change', function (val) {
console.log('change... now val is ' + val);
});
EventCenter.fire('change', 'Tom');
EventCenter.off('change');//events[change]就被刪除了
//所以不會(huì)再調(diào)用change相關(guān)方法(通知),delete原理就是刪除數(shù)組里面的元素(即方法)
</script>