• 一篇文章图文并茂地带你轻松学完 JavaScript 设计模式(二)


    JavaScript 设计模式(二)

    本篇文章是 JavaScript 设计模式的第二篇文章,如果没有看过我上篇文章的读者,可以先看完 上篇文章 后再看这篇文章,当然两篇文章并没有过多的依赖性。

    5. 代理模式

    代理模式提供了对目标对象的另一种访问机制。

    vue3 还没出来之前,我猜过可能会使用 proxy 取代 defineProperty ,结果也被验证了,毕竟 proxydefineProperty 支持更多的拦截机制,可以对数组的方法进行拦截。

    const obj = {};
    
    const proxyObj = new Proxy(obj, {
      set(target, prop, value, receiver) {
        console.log("set:", prop, "=", value);
        Reflect.set(target, prop, value, receiver);
      },
    });
    
    proxyObj.a = 1
    

    上述代码是用一个拦截器 Proxy 作代理,使得每次在改变属性的时候,都能打印相应的日记,实际上如果 set 内部改成 render 函数,就可以做到数据改变的时候,渲染页面了。

    6. 迭代器模式

    迭代器模式能让我们不用在意数据真实的存储结构,更好的获取数据。

    下面是一个迭代器模式的例子。

    实际上由于原生的 JavaScript 不支持对象进入 for of 循环,原因是因为对象没有一个关于迭代器的 Symbol 属性。

    如果要支持的话,可以用下面的做法。

    function* gen(obj) {
      const keys = Object.keys(obj);
      for (let i = 0; i < keys.length; i++) {
        const key = keys[i];
        yield [key, obj[key]];
      }
      return;
    }
    
    const obj = {
      a: 1,
      b: 2,
      c: 3,
    };
    
    for (let [key, value] of gen(obj)) {
      console.log(key, value);
    }
    
    // or
    // obj[Symbol.iterator] = gen.bind(this, obj);
    // for (let [key, value] of obj) {
    //   console.log(key, value);
    //}
    

    Generator 函数返回一个 迭代器用于迭代,而 for of 循环利用的就是这个迭代器。

    7. 装饰器模式

    ES7 语法提案中,尚未正式确定,因此主流浏览器都暂时不支持,但是有 babel 啊,这个神奇的工具可以帮助我们将 esnext 转化为浏览器可以执行的代码。

    bebel 的官网上可以转化 decorators

    const mixins = (...prototype) => {
      return (target) => {
        Object.assign(target.prototype, ...prototype);
      }
    }
    
    const readonly = (target, name, descriptor) => {
      descriptor.writable = false;
      return descriptor;
    }
    
    const prototype = {
      eat() {
        console.log("huro eat!")
      }
    }
    
    @mixins(prototype)
    class Person {
      @readonly
      name() {
        console.log("huro!!")
      }
    }
    
    const huro = new Person();
    huro.eat(); // huro!!
    
    // 我想改掉 huro 这个名字
    huro.name = () => {
      console.log("xxx");
    }
    // 修改无效
    
    huro.name() // huro!!
    

    利用装饰器模式,可以简化代码开发,很重要的一点是,装饰器也可以很好的起到注释的作用。

    8. 状态模式

    实际上 Promise 的实现中就用到了状态模式,当然也用到了观察者模式,关于 Promise 原理这块,给出简单的实现。并不遵循 Promise/A+ 规范。

    关于以下代码的一步一步实现,可以参考知乎的一篇文章 图解 Promise 实现原理(一)—— 基础实现

    enum Status {
      Pending = "Pending",
      Resolved = "Fulfilled",
      Rejected = "Rejected",
    }
    
    type PromiseFnType = (
      resolve: (data: any) => any,
      reject: (error: any) => any
    ) => any;
    
    interface Callback {
      onResolved: (data: any) => any;
      onRejected: (error: any) => any;
      resolve: (data: any) => any;
      reject: (error: any) => any;
    }
    
    class MyPromise {
      status: Status;
      value: any;
      callbacks: Callback[];
    
      constructor(fn: PromiseFnType) {
        this.status = Status.Pending;
        this.callbacks = [];
        this.value = null;
    
        fn(this.resolve.bind(this), this.reject.bind(this));
      }
    
      then(onResolved?: (data: any) => any, onRejected?: (error: any) => any) {
        return new MyPromise((resolve, reject) => {
          this.handle({
            onResolved,
            onRejected,
            resolve,
            reject,
          });
        });
      }
    
      handle(callback: Callback) {
        const { onRejected, onResolved, reject, resolve } = callback;
        if (this.status === Status.Pending) {
          this.callbacks.push(callback);
          return;
        }
        if (this.status === Status.Rejected) {
          let error = this.value;
          if (onRejected) error = onRejected(error);
          reject(error);
        }
        if (this.status === Status.Resolved && onResolved) {
          let value = this.value;
          if (onResolved) value = onResolved(value);
          resolve(value);
        }
      }
    
      reject(error: any) {
        this.value = error;
        this.status = Status.Rejected;
        this.callbacks.forEach((cb) => {
          this.handle(cb);
        });
      }
    
      resolve(value: any) {
        if (value instanceof MyPromise) {
          const then = value.then;
          then.call(value, this.resolve.bind(this), this.reject.bind(this));
          return;
        }
        this.value = value;
        this.status = Status.Resolved;
        this.callbacks.forEach((cb) => {
          this.handle(cb);
        });
      }
    }
    
    new MyPromise((resolve, reject) => {
      resolve(1);
    })
      .then((data) => {
        return new MyPromise((resolve, reject) => {
          resolve(data * 2);
        });
      })
      .then((data) => {
        console.log(data);
      });
    
    

    总结

    JavaScript 设计模式是程序设计中很重要的一个环节,在了解了各种设计模式之后,可以在遇到实际项目的时候,预先选择好一个好的设计模式用于开发,提高项目的可扩展性,也有助于我们理解源码。

  • 相关阅读:
    .NetCore 3.1和.NetCore 5.0 中WebApi的请求参数的验证方法
    php 使脚本持续的运行
    Elasticsearch es三种分页方式和对比
    es 大批量写入提高性能的策略
    php 使用多进程批量插入数据
    【转】EM算法MATLAB代码及详细注解
    【转】详解EM算法与混合高斯模型(Gaussian mixture model, GMM)
    【转】高斯混合模型
    【转】二维高斯分布(Two-dimensional Gaussian distribution)的参数分析
    word使用dot模板以spring word 模板为例
  • 原文地址:https://www.cnblogs.com/huro/p/14386028.html
Copyright © 2020-2023  润新知