从明天开始,我将间断更新javascript的设计模式,材料起源次要是https://www.patterns.dev/ 这里涵盖了所有的设计模式,次要内容来自对这个网站的翻译加上本人的了解,也是自我学习的过程

前沿

设计模式是软件开发的根本组成部分,因为在大型的软件设计过程中,常常会呈现一些设计模式,它能够用来优化咱们一些代码逻辑和解决形式
过来的一段时间中,web整个开发体系产生了迅猛的变动,尽管一些设计模式可能曾经没有了对应的价值,然而也有其中的一些设计模式曾经倒退到了解决一些古代问题
react置信大家都比拟相熟,在最近一段时间内取得了微小的关注,哦不对,始终以来react都备受关注,从npm包的下载量就能很显著的看进去,react始终稳居几大框架榜首

也因为react的风行,传统的设计模式曾经被批改优化,并且创立了新的设计模式,以便于在古代web开发中提供对应的价值,比方react的hook个性,能够代替很多传统设计模式,所以才有了这个专题,心愿可能通过一起学习将设计模式的实现、益处、缺点以及面试通通拿下

单例模式

单例示意的是能够实例化一次的类,并且能够全局拜访。这个繁多的实例能够在咱们的应用程序中共享,所以单例模式非常适合管理应用程序中的全局状态
咱们看一下单例到底是一个什么样的内容,咱们能够构建一个Counter类,它有以下办法

  • 返回实例(getInstance)
  • 返回计数器以后的值(getCount)
  • count值加一(increment)
  • count值减一(decrement)

    let counter = 0class Counter {getInstance() {  return this}getCount() {  return counter}increment() {  return ++counter}decrement() {  return --counter}}

    尽管上述的性能都实现了,然而这个类实际上是不符合标准的,标准规定的是这个类只能实例化一次,然而下面的代码咱们能够创立很多Counter实例

    const counter1 = new Counter()const counter2 = new Counter()console.log(counter1.getInstance() == counter2.getInstance()) // false

    通过两次实例化的形式之后,获取到的实例并不相等,两个实例只是不同实例的援用

    只能一个实例

    确保咱们只能创立一个实例的方法是创立一个名为instance的变量,在构造函数中,咱们能够在创立实例的时候将实例设置为对实例的援用,而后查看instantce变量是否曾经有值来避免反复实例化,如果曾经实例化,则抛出谬误让用户晓得曾经存在了实例

    let counter = 0let instance = nullclass Counter {constructor() {  if(instance) {    throw new Error("只能有一个Counter实例")  }}getInstance() {  return this}getCount() {  return counter}increment() {  return ++counter}decrement() {  return --counter}}const counter1 = new Counter();const counter2 = new Counter();// Error: You can only create one instance!

    这样就不能创立多个实例了

    Object.freeze

    这个时候咱们须要导出咱们的实例,然而在导出之前,咱们应该应用Object.freeze办法确保初始化实例不会被批改,升高应用危险

    const singletonCounter = Object.freeze(new Counter());export default singletonCounter;

    这样咱们就将singletonCounter导出了,咱们能够在任意JavaScript文件应用singletonCounter
    在不同的文件调用,数据都是共享的,都可能扭转counter值,并且可能读取到最新的值

    优缺点

    将实例化限度为一个实例会节俭大量内存空间,不必每次都给新的实例分配内存,在整个利用中这个实例都可能被援用,然而单例模式被认为是一种反模式,应该在JavaScript中防止
    其它的编程语言中,比方java或者c++,不可能跟javascript一样间接创建对象,在面向对象的编程语言中,须要创立一个类,这个类会创立一个对象,该创立的对象具备类实例的值,就像javascript中的实例值一样
    其实下面的一系列的操作,齐全能够应用一个简略的惯例对象来代替,比方

    let count = 0;const counter = {increment() {  return ++count;},decrement() {  return --count;}};Object.freeze(counter);export { counter };

    这样能够实现Counter类等价的成果
    还有一些暗藏危险,比方咱们在一个单例中引入了另一个单例,这里咱们创立了一个superCounter的实例,其中引入了Counter实例,在别的文件中如果引入Counter实例可能就会造成危险,一旦调用了super Counter,那Counter也会被扭转

    import Counter from "./counter";export default class SuperCounter {constructor() {  this.count = 0;}increment() {  Counter.increment();  return (this.count += 100);}decrement() {  Counter.decrement();  return (this.count -= 100);}}

    总结

    一个单例实例应该可能在整个利用中被援用,领有全局行为也会被感觉是一个蹩脚的设计,因为你能够随便更改它,然而你并不知道你到底在哪里更改了它
    在react中,常常通过redux或者react context等状态管理工具来进行全局状态治理,而不是应用单例模式,即便它们看起来这么像单例模式,这些工具提供了只读状态而不是单例的可变状态,应用redux时,只有纯函数的reducer能够在组建外部通过调度程序发送action进行状态更新,这些工具也存在全局状态的毛病,然而它能够让全局状态依照咱们制订的规定或者程序产生扭转