javascript设计模式及应用场景

栏目: JavaScript · 发布时间: 4年前

内容简介:这里花几分钟时间来讲解几个设计模式以及它们的应用场景。可以帮助你在平时开发时把设计模式用起来废话不多说,直接上demo目前浏览器不支持装饰器模式,如果想要让这段代码跑起来的话,需要依赖babel的一个插件:babel-plugin-transform-decorators-legacy

这里花几分钟时间来讲解几个 设计模式 以及它们的应用场景。可以帮助你在平时开发时把设计模式用起来

  • 装饰器模式
  • 迭代器模式
  • 发布订阅模式
  • 工厂模式
  • 单例模式
  • 代理模式
  • 外观模式

废话不多说,直接上demo

装饰器模式

装饰器DEMO

<!--index.js-->
function decoratorHoc(target){
    target.customerName = 'xuqiang';
}

@decoratorHoc
class Person{}

console.log(Person.customerName);
复制代码

装饰器疑问 ️

  • decoratorHoc是个函数,为何支持@decoratorHoc?不要把这个当作理所当然。可以试下把代码拷入vscode,然后code runner,发现报了这段错
javascript设计模式及应用场景

目前浏览器不支持装饰器模式,如果想要让这段代码跑起来的话,需要依赖babel的一个插件:babel-plugin-transform-decorators-legacy

那么下面三步来把babel环境搞一下

  • 安装全局babel
<!--在当前index.js目录下-->
yarn add babel-cli -g

yarn add babel-plugin-transform-decorators-legacy
复制代码
  • 配置.babelrc
<!--在当前index.js目录下新建.babelrc文件,内容如下-->
{
    plugins: ['transform-decorators-legacy']
}
复制代码
  • 编译index.js
<!--在当前index.js目录下-->
babel index.js --out-file compiled.js
复制代码

这里把index.js编译为了compiled.js。然后code runner compiled.js,发现日志输出了"xuqiang"

javascript设计模式及应用场景

至此你就实现了装饰器decoratorHoc

装饰器模式应用场景

装饰器模式可以说是非常方便地扩展了一个对象。那么平时开发中是不是有几类代码跟装饰器模式很相似

  • react的高阶组件
  • dva的@connect

这里就举两个例子,更多场景需要你自己去发现了

迭代器模式

迭代一个对象,就可以称为是迭代器,下面从es6的迭代器来讲解下

for-of遍历json

这是一个es6的自定义迭代器DEMO,讲解如何写一个迭代器来遍历普通对象,因为遍历数组内置已经支持了

let obj = {
    name: 'xuqiang',
    age: 20,
    [Symbol.iterator]: () => {
        let props = Object.keys(obj), i = props.length;
        return {
            next(){
                if(i > 0){
                    i = i - 1;
                    return {
                        value: obj[props[props.length - i - 1]],
                        done: false
                    };
                }else{
                    return {
                        value: '',
                        done: true
                    };
                }
            }
        };
    }
}

for(let prop of obj){
    console.log(prop);
}
复制代码

code runner发现可以正确遍历一个Object了

javascript设计模式及应用场景

发布订阅模式

发布订阅的场景

用一个老生常谈的场景先来解释下发布订阅,那就是学生时代的订牛奶,先来整理下需求

  • 有一个工厂,有一个let products = {},有一种属性叫做牛奶。此属性对应一个数组,数组存储每个订奶牛人的数据。
  • 工厂有一个定时器,每天早上8点开始遍历products,进行牛奶派发
  • 有很多消费者,向工厂订牛奶

需求整理清楚了,下面用个DEMO来实现下

// 发布订阅模式
// 发布订阅模式

class Puber{
    constructor(name){
        this.name = name;
        this.products = {};
        this.startInterval();
    }

    startInterval(){
        setInterval(() => {
            for(let prop in this.products){
                if(this.products.hasOwnProperty(prop)){
                    this.emit(prop);
                }
            }
        }, 3000);
    }

    sub(evt, cb){
        if(!this.products[evt]){
            this.products[evt] = [];
        }
        this.products[evt].push(cb);
    }

    emit(evt){
        if(this.products[evt]){
            let cbs = this.products[evt];
            for(let cb of cbs){
                cb && cb();
            }
        }
    }
}

class Suber{
    constructor(name){
        this.name = name;
        this.puber = new Puber('徐强');
    }

    getPuber(){
        console.log(`我是${this.name},我的牛奶配送员是${this.puber.name}`);
    }

    sub(evt, cb){
        this.puber.sub(evt, cb);
    }
}

let customer1 = new Suber('刘思琪');
customer1.getPuber();
customer1.sub('牛奶', () => {
    console.log(`现在时间是${+new Date},牛奶送至未来科技城,收件人:刘思琪`);
});

let customer2 = new Suber('徐大佬');
customer2.getPuber();
customer2.sub('牛奶', () => {
    console.log(`现在时间是${+new Date},牛奶送至空港新城,收件人:徐大佬`);
});
复制代码
javascript设计模式及应用场景

发现刘思琪和徐大佬,已经成功订了牛奶,并且每天早上10点钟开始派发牛奶了。当然了,这里没有写取消订牛奶的操作,大家可以自己接着写

工厂模式

class jQuery{
    constructor(name){
        this.name = name;
    }
}

function $(name){
    return new jQuery(name);
}

let obj1 = $('xuqiang');
let obj2 = $('liusiqi');
console.log(obj1);
console.log(obj2);
复制代码

工厂模式总结

这里举例也是用的jquery,可以发现jquery的$函数就是用了工厂模式,那么工厂模式有哪些好处呢?

  • 不需要自己调用new jQuery。直接用$很方便
  • 类似React.createElement,屏蔽了开发者直接使用new VNode,符合开放封闭原则,VNode的实现对开发者不可见

单例模式

光是单例模式的话比较简单,感觉没什么亮点,所以这里结合装饰器模式来写一个单例模式

写一个装饰器模式+单例模式的骚操作

function getInstanceHoc(target){
    target.getInstance = (() => {
        let instance;
        return () => {
            if(!instance){
                instance = new Function(`return new ${target}()`)();
            }
            return instance;
        }
    })();
}

@getInstanceHoc
class Person{
    eat(){
        console.log('i am eating');
    }
}

let obj = Person.getInstance();
console.log(obj);
obj.eat();

let obj1 = Person.getInstance();
console.log(obj === obj1);
复制代码

code runner之后发现,obj和obj1都可以eat了,然后比较obj===obj1,发现是true,说明单例模式已经成功了

javascript设计模式及应用场景

代理模式

用es6的Proxy来讲一下代理

class Vue{
    constructor(data){
        let _data =  data;

        return new Proxy(this, {
            get(target, key){
                return _data[key];
            },
            set(target, key, val){
                _data[key] = val;
            }
        });
    }
}

let obj = new Vue({
    name: '徐强',
    age: 20
});
console.log(obj.name);
obj.name = '刘思琪';
console.log(obj.name);
复制代码
javascript设计模式及应用场景

外观模式

外观模式在jquery中很常见。在我们平时开发中感觉也很好用

function winAlert(title, message, buttons, cb){
    if(cb === undefined){
        cb = buttons;
        buttons = null;
    }

    console.log(title);
    console.log(message);
    console.log(buttons);
    console.log(cb);
}

winAlert('提示', '操作完成', ['确认', '取消'], () => {});

winAlert('提示', '操作完成', () => {});
复制代码

运行结果:

javascript设计模式及应用场景

这让我想起目前业务中后端所有接口都是app/htmlGateway.do,只是version,rd等参数区别,从某种角度来说这是符合外观模式的。封闭后端api的内部实现,开放htmlGetway给前端调用

但是目前这种方式有个问题是,对于yapi,rap2等mock平台不太友好。因为api路径都是一致的,会不太好mock,也可能是因为我没有发现解决方案吧,所以觉得不太好mock

ok 这几种设计模式的demo都已经讲完了。有问题可以一起谈论。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

XML完全探索

XML完全探索

Steven Holzner / 中国青年出版社 / 2001-10 / 89.00

《XML完全探索》是完全根据读者的需要而设计的,书中有大量实际的XML场景。是一本尽可能深入地阐述XML的书籍,与其他XML书籍不同,本书中给出了上百个示例代码,完全测试通过,可供使用。 本书将帮助您:精通所有的从XML语法到XLink、从 XPointer到XML模式的XML标准;使用XSL和XSL格式化对象;使用XML和层叠样式表;利用Java和JavaScript,使用DOM解析器和一起来看看 《XML完全探索》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

URL 编码/解码
URL 编码/解码

URL 编码/解码

MD5 加密
MD5 加密

MD5 加密工具