太上老俊

js设计模式

本文纯粹是看完《js设计模式》之后的私人笔记,总结语句只为自己参考。

第一部分:面向对象

1、对象收编:用变量的属性收拢方法,以免过多方法独立在页面上增加被重写风险
2、类的概念:用this关键字给每个new的变量增加独立的方法属性;但此过程有性能消耗,所以如果有公用的方法,可以写在类的prototype上,给所有实例的对象公用。
3、使用return this,让函数级联调用:如a.b().c();
4、对象的安全模式:为避免忘记加new关键字,在类函数中判断this,若this指向window,则说明未添加new关键字,此时可以return new A(...);
5、类式继承:将子类的原型赋值为父类的实例对象;缺点:对父原型的操作影响到所有子对象,无法向父类传参
6、构造函数继承:利用call函数,给子类对象附上父类的属性和方法,但是附不上父类的原型(prototype),创建出来的父类方法属性对子类都独立
7、组合继承:结合5、6;缺点:每次创建对象的时候,要执行两次父类的对象(赋值原型时:将父的方法属性和父原型的方法属性添加到子;call时候:将父的方法属性添加到子;和赋值原型时重复了部分。导致前面那次只有后半部分有效,只有父的prototype是起了作用,父内部的属性方法都因call,导致原型上的无用,浪费)
8、原型式继承:没啥卵用,就是类式继承的封装
9、寄生式继承:貌似也没啥卵用,就是原型式继承的第二次封装,然后拓展;8和9都是为10做铺垫的
10、寄生组合:寄生式继承+构造函数继承;为解决组合继承中的缺点,call只添加父的方法属性到子,寄生只添加父的原型到子的原型;但不能直接把父的原型赋值给子的原型,因为这样改变了子原型中的constructor,所以需要用寄生,在里面重写子的原型的constructor;也解决了在继承原型时没执行父的构造函数,节省性能。缺点:这样继承之后,如果想给子原型添加方法属性,只能通过prototype.xxx来添加,如果用子.prototype = xxx ,则会删掉子对父原型的继承。
11、多继承:利用extend作用,遍历父对象(多个)属性方法给子;缺点:很多,父会替换掉子同名属性方法;无法实现子类公用属性方法(如果是深度复制,就都不能公用,如果潜复制,则引用类型可能公共),因此这种做法只在特定需求情况下。
12、多态:根据传入的arguments的长度实现不同逻辑;(注:arguments不是数组,typeof arguments='object',但是有length属性;所以arguments不能使用数组方法,如slice,一定要转换一下才可以:[].slice.call(arguments),和这个类似的有获取元素子节点等等)

 

第二部分:创建型设计模式:处理对象创建的设计模式,通过一些方法控制对象创建带来的问题

  • 简单工厂模式

    将各种小类创建整合到大类中,如篮球、足球,可以一个大工厂球类来整合,用户只要知道传什么参数到球类工厂,能得到什么就行。球类工厂里可以创建其他对象的公有属性方法,也可以case某个代表类型的参数拓展具体的球类对象。缺点:每次新增小类的生活,需要修改大类的case,

  • 工厂方法模式

    将子类的创建过程放入大类的方法中,然后用户直接传入参数获取大类的某个属性方法,这个方法就是创建该子类的过程;如 Factory[type](content);//type是Factory的某个方法,用来创建子类,content为传入子类的参数;

  • 抽象工厂模式

    抽象工厂只创建抽象类,抽象类的定义为:只显性声明方法,不负责具体方法的实现,抽象类中所有方法里面都抛异常,若子类继承了抽象类,但未重写某方法的实现,则可以获得相应提醒。抽象类在js中应用看场景而定,不像java那么广泛。

  • 建造者模式

    建造者模式是指将一个大类里面的某些功能封装成小类,然后组装成一个大类,如:Human为一个大类,Hand和Foot是小类,则Human中通过某个属性去实例化Hand和Foot,以及其他部分,共同构建出一个类;此方式对于颗粒度太小或小类复用率不高的情况下,不建议使用。会增加结构的复杂程度。

  • 原型模式

    就是将可共用的属性方法提出来放在类的原型中,然后通过寄生组合继承,实现子类;减少对象在实例化的消耗;

  • 单例模式

    就是用一个命名空间收拢其他的属性方法。避免函数重名,并且只实例化一次;通常用闭包管理私有变量;如var A = {A1:...;A2:...}

 

第三部分:结构型设计关注如何将类或对象组合成更大更复杂的结构,以简化设计。

  • 外观模式

    给用户提供统一的接口调用,用户看到的只有一个;如浏览器的监听,attachEvent和addEventListener,封装成一个addEvent,对用户来说,只需要关心外面包装好的,不用关心里面;

  • 适配器模式:

    适配器模式通常用来处理两个对象之间的接口不兼容的问题,比如我用wasuTv3框架替代wasuTv3;过度阶段,引入两个框架,但在tv2中对部分方法将tv3的实现直接调用

  • 代理模式

    略??

  • 装饰着模式

    不改变对象的基础上,通过拓展(给对象添加方法或属性),使对象满足更多需求;如A.a这个是基础方法,在子类调用了A.a后再执行一个其他的拓展方法,这个方法则为装饰者,满足拓展又不影响原来

  • 桥接模式

    桥接模式:

  • 组合模式

    将一个大类分成好多小块,小块之间组合,层次可以很多,最终成形大类;react思想

  • 享元模式

    将一些细微颗粒度的方法独立,提供给所有功能一致的对象使用;如游戏中所有人物的移动;分页操作的渲染页面;都可根据外部传入的一些参数,完成固定模式的计算;实现对象的功能;

 

第四部分:行为型设计模式:用于不同对象之间职责划分或算法抽象,不仅仅涉及类和对象,还涉及类或对象之间的交流模式并加以实现

  • 模板方法模式

    类似于之前播控重构里的组件基类,作用是提供给别的组件作为模板一样继承。已达到共用方法的目的

  • 观察者模式

    观察者模式共两个角色:观察者和订阅者,观察者提供三个方法,注册订阅者,删除订阅者,发布消息;订阅者通过传入身份信息和订阅回调函数,在观察者中保存,在用户触发某部分修改时,观察者可触发发布消息方法,然后观察者通过内部方法直接调用订阅者的相应的回调函数;订阅者还可以删除;(注:删除订阅者时候,通过比对方法,若方法存在则删除,此处如果传入匿名函数,则obArr[name][i] === fn 永远为false,但若传入一个声明函数名,则为true);

  • 状态模式

    和工厂方法模式差不多意思,将状态作为对象的方法,通过传入方法名,直接调用,而不需要分支判断

  • 策略模式

    策略模式,和状态模式,工厂方法模式一个意思,只不过状态模式可能用于一个逻辑下的n中状态,简化判断分支,而策略模式是独立存在的功能方法,如Animation.css的各种动画属性,对外就是策略,内部则是完成独立的功能,跟对象本身可能关系不大,只提供解决问题的一些策略。

  • 职责链模式

    将一个复杂完整的需求拆分成不同职责小需求,如ajax请求、处理数据,渲染数据。。。每个部分固定传入的参数或调用的方法,输入固定的数据或调用固定的下一职责链的方法;优点:方便单元测试

  • 命令模式

    通过某种参数格式,调用对象里的方法同时传递数据,如:对象A中有一系列方法功能,我想完成它可能要先调用A.a().b().c()....如果A提供一个excute方法,约定好给这个方法传入一些指令及数据,然后按照规则解析这个指令,完成对一系列方法的调用

  • 访问者模式

    将于对象本身关联不大的方法提取,在访问者中封装好,在对象必要调用的时候,传入对象(call,apply)改变访问者中的this指向,使得对象执行访问者中的具体方法;

  • 中介者模式

    和观察者模式差不多,中介者只负责单向发布

  • 备忘录模式

    简单的说,就是缓存一些不需要实时更新的信息数据,避免二次请求,比如缓存每次去服务器请求的数据(如列表数据)

  • 迭代器模式

    类似于数组的each,或for循环,用户遍历处理对象的元素,有时用于简化对于一类循环的的重复性操作

  • 解释器模式

    按照某种规则,完成一个固定的逻辑。类似于一种映射,比如根据传入的数据,经过解释器映射出一个有规律的值。

 

技巧型设计:通过一些特定的技巧来解决组件的某些问题,一般通过经验总结得到

  • 链模式

    就是在方法中返回对象本身,实现链式调用。例子讲的好复杂。。。为毛?!!!

  • 委托模式

    事件代理,将子元素的事件绑定去掉,通过父元素绑定,然后判断e.target的对象定位具体被触发的子元素

  • 数据访问对象模式

    创建DAO,用来封装对数据(localStrorage)的操作,提供方便安全的数据增删改查。

  • 节流模式
    do

    将用户可能连续快速触发的事件,通过函数节流或防抖,将n毫秒内触发的事件,只执行一次,间隔了n毫秒之后的才开始执行,达到性能优化及避免不可预知的bug

  • 简单模板模式

    将dom的结构数据化,再通过格式化字符串方式,用数据映射出html代码。 减少dom的操作,以提高性能。

  • 惰性模式:对于一些只需要执行一次的分支判断,采用惰性模式,重定义方法,避免每次调用都重复执行分支判断。 一般用于解决浏览器兼容(功能验证)分支代码的重写。
     
  • 参与者模式: 特定的作用域中执行给定的函数,并将参数原封不动的传递; 
    我的理解:参与者,让对象参与到其他函数执行过程中,导致this对象改变,这个过程称作函数绑定; 再通过函数柯里化,实现参数从绑定的过程中透传。
  • 等待者模式:给每个异步的开始时注入一个监听器,在事件处理结果时改变监听器的状态,每次改变监听器状态的同时,遍历所有异步监听事件的状态,若都处理完成,则统一处理所有异步执行结果。 
    问题:如果异步结果的返回相互依赖怎么办?
  • 同步模块模式:对模块进行分而治之的做法;核心分为模块定义,模块调用。 
    实际的过程为,创建一个命名空间,在模块定义方法里按照传入的参数定义模块链,在模块调用方法里,按照参数搜索出模块并返回到回调函数中使用,已达到对模块
  • 异步模块模式:当开启一个方法A,依赖于未加载的模块,依次加载模块(loadModule)并记录异步加载模块的数量(loadCount),load的过程中会缓存该模块,然后动态加载js,并设置回调函数来改变loadCount,当所有模块都加载完,会通过校正模块setModule将所得到的模块对象传入方法A内并执行。模块加载的过程也会寻找该模块本身的依赖,若依赖模块存在,则添加回调函数,若不存在,则按原路加载模块。

  • MVC:mvc模式将页面分成三个清晰的层次:数据(M)、视图(V)、控制器(C);目的为数据层只负责数据的存取,视图层根据数据生成对应视图,控制层则获取视图层和数据层,根据需求添加各种逻辑事件。从而解决页面各个层次之间的耦合,专注每个层次的独立功能即可。也可达到视图和数据的复用共享。
  • MVP:衍生于MVC,分为数据(M),视图(V),管理层(P); 
    主要思想为,原先在C中的生成视图的功能放到P中,V只根据传入的参数,生成视图模板(<div>{#data#}</div>);然后在P中根据M中获取的data和V中获取的tpl,生成最后的视图,并未视图添加交互逻辑和监听事件。其主要的不同为,独立了V层,让v变得更纯粹,也避免了因M的改变带来的V层的动荡。 

    模块化MVP:将MVP的实现封装,并提供构造函数,由于MVP中只有M和P是可改变的(V因只负责模板生成故不变),所以构造函数只提供setData和addP的接口方法,遇到模块化开发,就可调用改MVP模块,然后添加data和P,实现模块的MVP模式。
  • MVVP:

 

代码:https://github.com/laojun/jsBuild

 

posted on 2017-06-14 15:06  太上老俊  阅读(152)  评论(0编辑  收藏  举报

导航