• 前端设计模式


    SOLID设计原则

    • s: 单一原则:一个类只做一种类型责任,当这个类需要承当其他类型的责任的时候,就需要分解这个类
    • o: 开放封闭原则:对外扩展是开放的,对于修改是封闭的
    • l: 里氏置换原则:当一个子类的实例应该能够替换任何其超类的实例时,它们之间才具有is-A关系
    • i: 接口分离原则:使用多个专门的接口比使用单一的总接口总要好
    • d: 依赖倒置原则: 抽象不应该依赖于细节,细节应该依赖于抽象

    单例模式

    单例就是保证一个类只有一个实例,实现方法一般是先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返回

    应用场景
    在Jquery中

    jquery中只会创建一个$对象,会先去判断$对象是否存在,如果不存在创建一个新的对象

    if(window.jQuery!=null){
      return window.jQuery;
    }else{
        //init~~~~~~~
    }
    
    
    模态窗口

    一般网站都会有用户系统,登录窗口或者toast提示,会去创建一个getInstance的静态方法来统一调用

    工厂模式

    工厂模式主要出现在面向对象创建实例的过程中,其本质是为了更方便生成实例,构造函数和工厂方法分离。

    应用场景
    React.createElement
    class Vnode(tag, attrs, children){
        ……
    }
    
    React.createElement = function(tag, attrs, children) {
    	return new Vnode(tag, attrs, children)
    }
    
    jquery

    当我们在使用jquery的时候,直接返回的是一个jquery实例,而不是需要new Jquery(′div′)才能够返回

    class JQuery{
        construtor(selector){
            ……
        }
        ……
    }
    
    window.$ = function(selector) {
      return new JQuery(selector);
    }
    

    函数缓存(备忘模式)

    高阶函数

    高阶函数就是那种输入参数里面有一个或者多个函数,输出也是函数的函数,这个在js里面主要是利用闭包实现的,最简单的就是经常看到的在一个函数内部输出另一个函数,每次执行都会缓存方法执行的结果

    适配器模式

    适配器模式是一对相对简单的模式。但适配器模式在JS中的使用场景很多,在参数的适配上,有许多库和框架都使用适配器模式;数据的适配在解决前后端数据依赖上十分重要。我们要认识到的是适配器模式本质上是一个”亡羊补牢”的模式,它解决的是现存的两个接口之间不兼容的问题,你不应该在软件的初期开发阶段就使用该模式;如果在设计之初我们就能够统筹的规划好接口的一致性,那么适配器就应该尽量减少使用。

    适配器模式不会增加或者减少接口的功能,提供一个不同的接口

    应用场景
    React-Redux

    redux为了和react适配,所有有mapStateToProps()这个函数来吧state转为Props外部状态,这样就可以从外部又回到组件内了。你看这个就是适配器模式(Adaptor)

    观察者模式

    • 发布 && 订阅
    • 一对N(一对一,一对多)

    Promise实现

    function Promise(fn) {
        // 加入状态
        var state = 'pending';
        var value = null;
        //callbacks为订阅数组,因为可能同时有很多个回调
        var callbacks = [];  
        //加入订阅数组
        this.then = function (onFulfilled) {
            if(state==='fullfilled'){
                callbacks.push(onFulfilled);
                //支持链式调用
                return this;
            }
        };
        //遍历订阅回调数组,执行回调
        function resolve(value) {
           // 加入setTimeout,保证先注册then,然后在执行回调
           setTimeout(function() {
            state = 'fulfilled';
            callbacks.forEach(function (callback) {
                callback(value);
            });
        }, 0)
        }
    
        fn(resolve);
    }
    
    参考

    30分钟,让你彻底明白Promise原理

    Events模块

    node.js中有一个底层的Events模块,被其他的模块大量使用,可以说是node非常核心的一个模块了.其本质还是一个观察者模式

    const eventEmitter = require('events').EventEmitter
    
    const emitter1 = new eventEmitter()
    
    emitter1.on('some', info=> {
        console.log('fn1', info)
    })
    emitter1.on('some', info=> {
        console.log('fn2', info)
    })	
    emitter1.emit('some', 'xxxx')
    
    
    vue中的watch函数

    vue有个订阅数据中心,有订阅队列、发布方法、还有通知方法

    生命周期

    还有vue与react中的生命周期钩子,下面是vue源码,在new Vue的时候使用callHook方法执行我们定义的方法

    迭代器模式

    迭代器模式就是为了简化有序集合的遍历产生的模式,统一遍历的方式,在ES6中通过Symbol.iterator标识数据是可遍历的

    function each(data, callback) {
        //通过js提供的Symbol.iterator返回迭代器
        const iterator = data[Symbol.iterator]()
        let item = {done: false}
        while(!item.done) {
            item.iterator.next()
            if(!item.done) {
                callback(item)
            }
        }
    }
    let log = (data)=>{
        console.log(data)
    }
    
    let arr = [1,2,3,4,5,6]
    let map = new Map()
    map.set('a', 100)
    map.set('b', 200)
    
    each(arr)
    each(map)
    

    拥有迭代器模式的数据,可以通过for……of语法糖来遍历

      for(let item of data) {
            cb(item)
    }
    

    装饰器模式

    装饰器它能够动态为一个函数、方法或者类添加新的行为,而不需要通过子类继承或直接修改函数的代码来获取新的行为能力

    • 为对象添加新的功能(扩展功能)
    • 不改变原有的结构和逻辑
    应用场景
    简单案例
    @test
    class Demo{
        
    }
    
    function test(target){
        target.isDec=true
    }
    
    alert(Demo.isDec)
    
    @test(true)
    class Demo{
        
    }
    
    function test(isDec){
       return function(target) {
            target.isDec=isDec
       }
    }
    
    alert(Demo.isDec)
    
    函数柯里化
     const curry = func => (...rest) => {
                // coding here
                var length = func.length;
                let arr = [].concat(rest)
                let temp = function (..._rest) {
                    arr = arr.concat(_rest)
                    if (arr.length === length) {
                        func(...arr)
                    }
                    return temp
                }
                return temp
            };
    
            const fn = curry(function (x, y, z) {
                console.log(x, y, z);
            });
    
            // 保证以下方式皆可调用成功,能够打印一次性出 4 次 1 2 3
            fn(1, 2, 3);
            fn(1, 2)(3);
            fn(1)(2)(3);
            fn(1)(2, 3);
    
    React-Redux
    class TodoListContainer extends React.Component {
    }
    
    
    export default connect(
      mapStateToProps,
      mapDispatchToProps
    )(TodoListContainer)
    
    
    
    // 源码实现
    
    connectHOC = connectAdvanced;
    mergePropsFactories = defaultMergePropsFactories;
    selectorFactory = defaultSelectorFactory;
    function connect (
      mapStateToProps,
      mapDispatchToProps,
      mergeProps,
      {
      pure = true,
      areStatesEqual = strictEqual, // 严格比较是否相等
      areOwnPropsEqual = shallowEqual, // 浅比较
      areStatePropsEqual = shallowEqual,
      areMergedPropsEqual = shallowEqual,
      renderCountProp, // 传递给内部组件的props键,表示render方法调用次数
      // props/context 获取store的键
      storeKey = 'store',
      ...extraOptions
      } = {}
    ) {
      const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, 'mapStateToProps')
      const initMapDispatchToProps = match(mapDispatchToProps, mapDispatchToPropsFactories, 'mapDispatchToProps')
      const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps')
    
      // 调用connectHOC方法
      connectHOC(selectorFactory, {
        // 如果mapStateToProps为false,则不监听store state
        shouldHandleStateChanges: Boolean(mapStateToProps),
        // 传递给selectorFactory
        initMapStateToProps,
        initMapDispatchToProps,
        initMergeProps,
        pure,
        areStatesEqual,
        areOwnPropsEqual,
        areStatePropsEqual,
        areMergedPropsEqual,
        renderCountProp, // 传递给内部组件的props键,表示render方法调用次数
        // props/context 获取store的键
        storeKey = 'store',
        ...extraOptions // 其他配置项
      });
    }
    
    function connectAdvanced (
      selectorFactory,
      {
        renderCountProp = undefined, // 传递给内部组件的props键,表示render方法调用次数
        // props/context 获取store的键
        storeKey = 'store',
        ...connectOptions
      } = {}
    ) {
      // 获取发布订阅器的键
      const subscriptionKey = storeKey + 'Subscription';
      const contextTypes = {
        [storeKey]: storeShape,
        [subscriptionKey]: subscriptionShape,
      };
      const childContextTypes = {
        [subscriptionKey]: subscriptionShape,
      };
    
      return function wrapWithConnect (WrappedComponent) {
        const selectorFactoryOptions = {
          // 如果mapStateToProps为false,则不监听store state
          shouldHandleStateChanges: Boolean(mapStateToProps),
          // 传递给selectorFactory
          initMapStateToProps,
          initMapDispatchToProps,
          initMergeProps,
          ...connectOptions,
          ...others
          renderCountProp, // render调用次数
          shouldHandleStateChanges, // 是否监听store state变更
          storeKey,
          WrappedComponent
        }
    
        // 返回拓展过props属性的Connect组件
        return hoistStatics(Connect, WrappedComponent)
      }
    }
    
    属性只读

    只能执行,不能修改,使用到了Object.defineProperty() 的 属性描述descriptor 的 wirtebale 属性

    class Person{
        constructor(){
            this.first = "zhangsan0"
            this.last = "3"
        }
        
        @readonly
        name(){
            return `${this.first}${this.last}`
        }
    }
    
    function readonly(target,name,descriptor){
        descriptor.writebale = false
        return descriptor
    }
    
    日志打印
    class Math {
    
        @log
        add(a,b){
            return a+b
        }
    }
    
    function log(target,name,descriptor) {
    
        let oldValue = descriptor.value
        descriptor.value = function() {
            console.log('日志打印')
            return oldValue.apply(this,arguments)
        }
        return descriptor
    }
    
    const math = Math();
    //console.log('日志打印')
    const result = math.add(100,33); 
    

    在日常开发中,可用其用来进行日志打印,埋点上报

    代理模式

    代理模式不愿意或者不想对原对象进行直接操作,我们使用代理就是让它帮原对象进行一系列的操作,代理和本体接口保持一致性,提供一模一样的接口

    场景
    事件代理
     <div class="container">
        <a>1</a>
        <a>2</a>
        <a>3</a>
        <a>4</a>
        <a>5</a>
    </div>
        
     window.onload = function () {
        document.getElementsByClassName('container')[0].addEventListener('click', function (e) {
            if (e.target.nodeName === "A") {
                alert(e.target.innerHTML)
            }
        })
    }
    
    ES6 Proxy
    const list = [1, 2];
    
    const observer = new Proxy(list, {
      get: function(target,key){
        // 代理处理,如果获取的是元素的第二个元素
         if(key==1){
             return 3;
         }
      },
      set: function(target, key, value, receiver) {
        console.log(`prop: ${value} is changed!`);
        return Reflect.set(...arguments);
      },
    });
    observer[3] = 4;
    console.log(observer[1])
    

    外观模式

    它为子系统中的一组接口提供一个一致的界面, Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。引入外观角色之后,使用者只需要直接与外观角色交互,使用者与子系统之间的复杂关系由外观角色来实现,从而降低了系统的耦合度

    场景
    批量设置style

    将多个样式设置批量设置

    function setStyles( id, styles ){
        var element = document.getElementById( id );
        for( var key in styles ){
            if( styles.hasOwnProperty( key ) ){
                element.style[ key ] = styles[ key ];
            }
        }
    }
    
    setStyles( 'content', {
        color : 'red',
        height : '200px'
    } );
    
    组件库设计

    在组件目录中,统一有个出口 index.tsx 包括了各个子组件的引用,统一 export

  • 相关阅读:
    9、spring五种scope
    2、数据库四种事务隔离级别
    4、jquery获取servlet值
    3、$.post不执行
    A brief Arch installation in VMware
    Git经验记录
    Windows上virtualenv搭建python开发环境
    no such file django-admin.py
    复制拷贝函数+重载operator=
    Reconfigure CentOS+freeradius+daloradius again
  • 原文地址:https://www.cnblogs.com/fuGuy/p/12862941.html
Copyright © 2020-2023  润新知