JavaScript系列教程

JavaScript学习笔记(三十)-- 设计模式

2020-07-22  本文已影响0人  千锋HTML5学院

设计模式

单例模式

核心代码

// 准备一个构造函数
// 将来要 new 的
function Person() {}
// 准备一个单例模式函数
// 这个单例模式函数要把 Person 做成一个单例模式
// 将来再想要 new Person 的时候只要执行这个 singleton 函数就可以了
function singleton () {
    let instance;
    if (!instance) { // 如果 instance 没有内容
        // 来到这里,证明 instance 没有内容
        // 给他赋值为 new Person
        instance = new Person()
    }
    // 返回的永远都是第一次 new Person 的实例
    // 也就是永远都是一个实例
    return instance
}
​
const p1 = singleton()
const p2 = singleton()
console.log(p1 === p2) // true

应用

// 这个构造函数的功能就是创建一个 div,添加到页面中
function CreateDiv() {
    this.div = document.createElement('div')
    document.body.appendChild(this.div)
}
​
CreateDiv.prototype.init = function (text) {
    this.div.innerHTML = text
}
​
// 准备把这个 CreateDiv 做成单例模式
// 让 singleton 成为一个闭包函数
const singleton = (function () {
    let instance
    return function (text) {
        if (!instance) {
            instance = new CreateDiv()
        }
        instance.init(text)
        return instance
    }
})()
​
singleton('hello') // 第一次的时候,页面中会出现一个新的 div ,内容是 hello
singleton('world') // 第二次的时候,不会出现新的 div,而是原先的 div 内容变成了 world

组合模式

class GetHome {
    init () {
        console.log('到家了')
    }
}
class OpenComputer {
    init () {
        console.log('打开电脑')
    }
}
class PlayGame {
    init () {
        console.log('玩游戏')
    }
}
class Compose {
    constructor () {
        this.compose = []
    }
    // 添加任务的方法
    add (task) {
        this.compose.push(task)
    }
    // 一个执行任务的方法
    execute () {
        this.compose.forEach(item => {
            item.init()
        })
    }
}
const c = new Compose()
// 把所有要完成的任务都放在队列里面
c.add(new GetHome())
c.add(new OpenComputer)
c.add(new PlayGame)
​
// 直接器动任务队列
c.execute()
// 就会按照顺序执行三个对象中的 init 函数

观察者模式

一个例子

addEventListener

btn.addEventListener('click', function () {
    console.log('btn 被点击了')
})

书写代码

const observer = {
    message: {},
    on: function () {},
    emit: function () {},
    off: function () {}
}
class Observer {
    constructor () {
        this.message = {}
    }
    on () {}
    emit () {}
    off () {}
}

ON

class Observer {
    constructor () {
        this.message = {}
    }
    on(type, fn) {
        // 判断消息盒子里面有没有设置事件类型
        if (!this.message[type]) {
            // 证明消息盒子里面没有这个事件类型
            // 那么我们直接添加进去
            // 并且让他的值是一个数组,再数组里面放上事件处理函数
            this.message[type] = [fn]
        } else {
            // 证明消息盒子里面有这个事件类型
            // 那么我们直接向数组里面追加事件处理函数就行了
            this.message[type].push(fn)
        }
    }
    emit () {}
    off () {}
}

EMIT

class Observer {
    constructor () {
        this.message = {}
    }
    on(type, fn) {
        // 判断消息盒子里面有没有设置事件类型
        if (!this.message[type]) {
            // 证明消息盒子里面没有这个事件类型
            // 那么我们直接添加进去
            // 并且让他的值是一个数组,再数组里面放上事件处理函数
            this.message[type] = [fn]
        } else {
            // 证明消息盒子里面有这个事件类型
            // 那么我们直接向数组里面追加事件处理函数就行了
            this.message[type].push(fn)
        }
    }
    emit(type, ...arg) {
        // 判断你之前有没有订阅过这个事件
        if (!this.message[type]) return
        // 如果有,那么我们就处理一下参数
        const event = {
            type: type,
            arg: arg || {}
        }
        // 循环执行为当前事件类型订阅的所有事件处理函数
        this.message[type].forEach(item => {
            item.call(this, event)
        })
    }
    off() {}
}

OFF

class Observer {
    constructor () {
        this.message = {}
    }
    on(type, fn) {
        // 判断消息盒子里面有没有设置事件类型
        if (!this.message[type]) {
            // 证明消息盒子里面没有这个事件类型
            // 那么我们直接添加进去
            // 并且让他的值是一个数组,再数组里面放上事件处理函数
            this.message[type] = [fn]
        } else {
            // 证明消息盒子里面有这个事件类型
            // 那么我们直接向数组里面追加事件处理函数就行了
            this.message[type].push(fn)
        }
    }
    emit(type, ...arg) {
        // 判断你之前有没有订阅过这个事件
        if (!this.message[type]) return
        // 如果有,那么我们就处理一下参数
        const event = {
            type: type,
            arg: arg || {}
        }
        // 循环执行为当前事件类型订阅的所有事件处理函数
        this.message[type].forEach(item => {
            item.call(this, event)
        })
    }
    off (type, fn) {
        // 判断你之前有没有订阅过这个事件
        if (!this.message[type]) return
        // 如果有我们再进行移除
        for (let i = 0; i < this.message[type].length; i++) {
            const item = this.message[type][i]
            if (item === fn) {
                this.message[type].splice(i, 1)
                i--
            }
        }
    }
}

使用一下

const o = new Observer()
​
// 准备两个事件处理函数
function a(e) {
    console.log('hello')
}
​
function b(e) {
    console.log('world')
}
​
// 订阅事件
o.on('abc', a)
o.on('abc', b)
​
// 发布事件(触发)
o.emit('abc', '100', '200', '300') // 两个函数都回执行
​
// 移除事件
o.off('abc', 'b')
​
// 再次发布事件(触发)
o.emit('abc', '100', '200', '300') // 只执行一个 a 函数了

 
 
 
 
本文转自知乎号:千锋HTML5学院

上一篇 下一篇

猜你喜欢

热点阅读