IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> JavaScript常用设计模式总结+代码实现 -> 正文阅读

[JavaScript知识库]JavaScript常用设计模式总结+代码实现

1. 观察者模式

设计模式思路:

  • 变化的数据作为被观察者, 受改数据影响的元素/对象作为被观察者
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8">
    <title>观察者模式</title>
    <style>
        .container {
            width: 400px;
            background-color: mediumpurple;
            margin: 0 auto;
            overflow: hidden;
            text-align: center;
            padding: 30px
        }

        h2 {
            margin: 20px 0;
            color: indianred;
        }

        input {
            width: 80%;
            border-radius: 5px
        }

        .boxes {
            margin: 30px auto;
            width: 80%;
        }

        .box {
            width: 100%;
            height: 40px;
            background-color: #e5e6e4;
            border-radius: 10px;
            margin-bottom: 7px;
            line-height: 40px;
            font-weight: bold;
        }

        .active {
            background-color: #d2561c;
            color: #e5e6e4;
        }
    </style>

</head>
<body>
<div class="container">
    <h2>观察者模式实现</h2>
    <label>
        <input type="text">
    </label>
    <div class="boxes">
        <!-- <div class="box" id="a">包含a</div>
         <div class="box" id="b">包含b</div>-->
    </div>
</div>
<script type="text/javascript">

    /**
     * 表单的数据, 作为被观察者
     */
    class Input {
        constructor(el) {
            this.observers = [];
            el.addEventListener("input", e => {
                this.notifyAll(e.target.value);
            })
        }

        notifyAll(value) {
            this.observers.forEach(ob => {
                ob.notify(value)
            })
        }

        addObserver(observer) {
            this.observers.push(observer)
        }
    }

    /**
     * 观察者基类, 可用继承此类的方式定义观察者
     */
    class Observer extends DocumentFragment {
        constructor(txt) {
            super();
            this.div = document.createElement("div")
            this.div.className = "box"
            this.div.innerText = txt;
            document.querySelector(".boxes").appendChild(this.div)
        }

        notify(value) {
            this.div.classList.toggle('active', this.handle(value))
        }
    }

    /**
     * 观察者实现类
     */
    class DefaultObserver extends Observer {
        constructor(txt) {
            super(txt);
            this.txt = txt;
        }

        handle(value) {
            return value.indexOf(this.txt) !== -1
        }
    }

    class NumberObserver extends Observer {
        constructor(txt) {
            super(txt);
        }

        handle(value) {
            return /\d/.test(value)
        }
    }

    const ipt = new Input(document.querySelector("input"));
    ipt.addObserver(new DefaultObserver("a"));
    ipt.addObserver(new DefaultObserver("b"));
    ipt.addObserver(new DefaultObserver("c"));
    ipt.addObserver(new NumberObserver('包含数字'))

</script>
</body>
</html>

2. 单例模式

2.1 设计原则

  • 无论程序员手动创建多少个对象, 存在的示例永远都只有一个

2.2 实现思路

  1. 使用闭包的特性, 一个函数内部返回另一个函数;
  2. 如果示例没有被创建过, 那么调用用户传递进来的回调函数,进行对象的创建并返回; 且将结果赋值给返回函数外部的那个变量(result)
  3. 如果示例已经被创建, 那么result必然不为null, 直接将result返回就可以啦, 这样就不会在去创建一个新对象了

2.3 Code

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8">
    <title>闭包实现单例模式</title>
    <meta content="width=device-width, initial-scale=1.0" name="viewport">
</head>
<body>
<button id="btn">登录</button>
<script>
    console.log(window)
    const createLogin = function (a, b, c) {
        console.log(a, b, c)
        const div = document.createElement('div')
        div.innerHTML = "登录弹窗"
        div.style.display = "none"
        document.body.appendChild(div)
        return div
    }

    const getSingle = function (cb) {
        let result;
        return function () {
            return result || (result = cb.apply(this, arguments))
        }
    }

    const create = getSingle(createLogin)
    document.getElementById("btn").onclick = () => {
        const element = create(1, 2, 3)
        element.style = {
            display: "block",
            color: "red"
        }
    }
</script>
</body>
</html>

3. 适配器模式

3.1 目的

  1. 为了解决两个接口不兼容的情况
  2. 不需要改变已有的接口, 通过包装一层的方式实现两个接口之间的正常协作
/**
 * 适配器模式
 */

//已有地图的接口
const googleMap = {
        show() {
            console.log("rendering google map...");
        }
    }

const baiduMap = {
    display() {
        console.log("rendering baiduMap...")
    }
}

//已有的渲染接口
const renderMap = function (map) {
    if (map.show instanceof Function) {
        map.show()
    }
}

//定义百度地图的适配器, 适配renderMap的show方法
const baiduMapAdapter = {
    show() {
        return baiduMap.display()
    }
}

//测试
renderMap(googleMap) //rendering google map...
renderMap(baiduMapAdapter) //rendering baiduMap...

4. 装饰模式

4.1 目的

  1. 不需要改变已有接口, 给对象添加额外的功能

4.2 实现

/**
 * 装饰模式
 */
function readonly(target, key, descriptor) {
    descriptor.writeable = false;
    return descriptor;
}

@readonly
class Man {
    name = "naruto"
}

let m = new Man()
m.name = "sasuke"

console.log(m.name)

5. 代理模式

5.1 目的

  1. 某些情况下,一个对象不适合或不能直接引用另一个对象, 而代理对象可以再两个对象之间起到中介的作用

5.2 实现

/**
 * 代理模式
 */

//示例1: 司机开车

class Car {
    drive(): string {
        return "driving"
    }
}

class Driver {
    public age: number;

    constructor(age: number) {
        this.age = age;
    }
}

class CarProxy {
    private driver: Driver;

    constructor(driver: Driver) {
        this.driver = driver;
    }

    drive(): string {
        if (this.driver.age < 18) {
            return "to yong to drive"
        }
        return new Car().drive();
    }
}

const driver = new Driver(19);
// @ts-ignore
const result = new CarProxy(driver).drive();

console.log(result);


//示例2: es6-proxy,在目标对象之间架设一层拦截
// @ts-ignore
const obj = {}

const proxy = new Proxy(obj, {
    get(target: {}, p: string | symbol, receiver: any): any {
        return Reflect.get(target, p, receiver)
    },
    set(target: {}, p: string | symbol, value: any, receiver: any): boolean {
        return Reflect.set(target, p, value, receiver)
    }
})


// @ts-ignore
proxy.count = 1;
// @ts-ignore
++proxy.count

// @ts-ignore
console.log(obj.count) //2

6. 发布, 订阅模式

6.1 目的

  • 实现对象间多对对的依赖关系
  • 通过事件中心管理多个事件
  • 目标对象并不直接通知观察者, 而是通过事件中心来派发通知

6.2 实现

//消息定义发布模式

declare interface IPubsub {
    list: Array<unknown>,
    addListener: (key: string, fn: Function) => void,
    publish: () => void
    removeListener: (key: string, fn: Function) => void | false
}

const shopObj: IPubsub = {
    //缓存列表,用来存放订阅函数
    list: [],
    //添加订阅者
    addListener: function (key, fn) {
        if (!this.list[key]) {
            this.list[key] = [];
        }
        this.list[key].push(fn);

    },
    //发布消息
    publish: function () {
        let key = Array.prototype.shift.call(arguments);
        const funcs = this.list[key];
        if (!funcs || funcs.length === 0) {
            console.log("no relevant subscriber")
            return
        }
        for (let i = 0; i < funcs.length; i++) {
            funcs[i].apply(this, arguments)
        }
    },
    //取消订阅

    removeListener(key: string, fn?: Function | null): void | false {
        const fns = this.list[key]
        if (fn === null) {
            fns.length = 0;
            return
        }
        if (!fns) {
            fns && (fns.length = 0);
            return false
        } else {
            for (let i = fns.length - 1; i >= 0; i--) {
                let _fn = fns[i]
                if (_fn === fn) {
                    fns.splice(i, 1)
                }
            }
        }
    }

}

//订阅者1
shopObj.addListener("xm", size => {
    console.log(`xm size is ${size}`)
})

//订阅者2
shopObj.addListener("张三", size => {
    console.log(`zhangsan size is ${size}`)
})

// @ts-ignore
//通知张三
shopObj.publish("张三", 120)

//张三取消订阅
shopObj.removeListener("张三", null)
// @ts-ignore
shopObj.publish("张三", 120)
//结果: no relevant subscriber

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-20 15:42:11  更:2021-09-20 15:42:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 22:05:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码