1、模組模式
在立即執行函式表示式中定義的變數和方法,在該函式外部是訪問不到的,只能通過該函式提供的介面,”有限制的”進行訪問;通過函式的作用域,解決了屬性和方法的封裝問題。
最常見的立即執行函式寫法有以下兩種:
(function(){ /* code */ }())
或者
(function(){ /* code */ })()
模組模式程式碼:
let Person = (function(){
var age = "12";
var name = "jerry";
function getAge(){
return age;
}
function getName(){
return name;
}
return {
getAge: getAge,
getName: getName
}
})()
console.log(age, `age`); // 報錯: Uncaught ReferenceError: age is not defined
console.log(name, `name`); // 空字串,為啥不報錯?看底部備註
console.log(Person.age); // undefined
console.log(Person.name); // undefined
// 只能通過Person提供的介面訪問相應的變數
console.log(Person.getName()); // jerry
console.log(Person.getAge()); // 12
2、建構函式模式
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.printName = function(){
console.log(this.name)
}
Person.prototype.printAge = function(){
console.log(this.age)
}
function Student(name,age){
// 繼承 Person 的屬性
Person.call(this,name,age)
}
function create(prototype){
function F(){}
F.prototype = prototype
return new F()
}
// 讓Student的原型指向一個物件,該物件的原型指向了Person.prototype,通過這種方式繼承 Person 的方法
Student.prototype = create(Person.prototype)
Student.prototype.printAge = function(){
console.log(this.age)
}
let student = new Student(`jerry`,12)
student.printName() // "jerry"
student.printAge() // "12"
3、混合模式
function Person(name,age){
this.name = name
this.age = age
}
Person.prototype.printName = function(){
console.log(this.name)
}
function Student(name,age){
// 繼承 Person 的屬性
Person.call(this, name, age)
}
function create(prototype){
function F(){}
F.prototype = prototype
return new F()
}
// 讓Student的原型指向一個物件,該物件的原型指向了Person.prototype,通過這種方式繼承 Person 的方法
Student.prototype = create(Person.prototype)
Student.prototype.printAge = function(){
console.log(this.age)
}
let student = new Student(`jerry`, 12)
student.printName() // "jerry"
student.printAge() // 12
4、工廠模式
function Person(name, age){
let person = new Object()
person.name = name
person.age = age
person.printName = function(){
console.log(this.name)
}
person.printAge = function(){
console.log(this.age)
}
return person
}
let person = Person(`jerry`,12)
person.printName()
person.printAge()
5、單例模式
let Singleton = (function(){
let instantiated
function init(){
/*定義單例程式碼*/
return{
publicMethod: function(){
console.log("Hello World");
},
publicProperty: "Test"
}
}
return{
getInstance: function(){
if(!instantiated){
instantiated = init()
}
return instantiated
}
}
}())
Singleton.getInstance().publicMethod()
單例之間的通訊:
建立兩個獨立的物件:jim&&lily,兩者之間通過door直接通訊,如果沒有新建door,有直接通訊。程式碼如下:
let jim = (function(argument){
let door
let jimHome = function(msg){
this.doorbell = msg
}
let info = {
sendMessage: function(msg){
if(!door){
door = new jimHome(msg)
}
return door
},
coming: function(){
return "來了來了"
}
}
return info
}())
let lily = {
callJim: function(msg){
let _xw = jim.sendMessage(msg)
alert(_xw.doorbell)
console.log(_xw.doorbell)
_xw = null // 等待垃圾回收
let coming = jim.coming()
console.log(coming)
}
}
lily.callJim("叮嚨")
6、釋出-訂閱模式
訂閱釋出模式定義了一種一對多的依賴關係,讓多個訂閱者物件同時監聽某一個主題物件。這個主題物件在自身主題變化時,會通知所有訂閱者物件,使他們能夠自動更新自己的狀態。
將一個系統分割成一系列相互協作的類有一個很不好的副作用:需要維護相應物件間的一致性,這樣會給維護、擴充套件和重用都帶來不便。當一個物件的改變需要同時改變其他物件,而且他不知道具體有多少物件需要改變時,此時建議使用訂閱釋出模式。
應用場景:
DOM事件。DOM事件是一種典型的釋出-訂閱模式,對一個DOM節點的DOM事件進行監聽;當操作DOM節點時,觸發相應的事件並執行函式。
自定義時間。指定釋出者,類似於一個物件(key:value);key表示事件的名稱,value是一個陣列;釋出訊息後,遍歷value的陣列,依次執行訂閱者的回撥函式。
應用Demo如下:
let Event = (function(){
var events = {}
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)
}
}
function off(evt){
delete events[evt]
}
return {
on: on,
fire: fire,
off: off
}
}())
Event.on(`change`, function(val){
console.log(`change事件,value is` + val)
})
Event.on(`click`, function(val){
console.log(`click事件,value is `+ val)
})
Event.fire(`change`, `jerry1`)
Event.fire(`click`, `jerry2`)
Event.off(`change`)
備註:console.log(name, `name`)沒有報錯,是因為name是瀏覽器的視窗變數名,已存在於瀏覽器內部。