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

最新文章

  1. Recurrent Neural Network系列1--RNN(循环神经网络)概述
  2. Python excel 库:Openpyxl xlrd 对比 介绍
  3. VS2010 ERROR:c1xx fatal error c1083
  4. 如何将MySQL help contents的内容有层次的输出
  5. 为什么获取的System.Web.HttpContext.Current值为null,HttpContext对象为null时如何获取程序(站点)的根目录
  6. Activiti系列: 如何在web中使用activiti和sql server
  7. phonegap 新窗口 WebView
  8. 团队软件开发_基于windows下截屏软件关于NABC框架的特点
  9. Javascript数据类型&mdash;&mdash;number类型
  10. 文本框脚本 - select 事件
  11. hdu - 4709 - Herding
  12. html&amp;css入门详解
  13. mybatis-generator 代码自动生成工具(maven方式)
  14. PHP设计模式:工厂方法
  15. Maven 新手入门+命令大全
  16. redis启动出错Creating Server TCP listening socket 127.0.0.1:6379: bind: No error(转)
  17. slfj+logback
  18. Maven常见jar包依赖
  19. HGOI20181030 模拟题解
  20. 理解FlumeNG的batchSize和transactionCapacity参数和传输事务的原理 【转】

热门文章

  1. Sentry(v20.12.1) K8S 云原生架构探索,SENTRY FOR JAVASCRIPT 故障排除
  2. Request&amp;Response总结
  3. JavaScript中函数的this指向!
  4. 无法获取 vmci 驱动程序版本: 句柄无效。 驱动程序 vmci.sys 版本不正确。请尝试重新安装 VMware Workstation。 打开模块DevicePowerOn电源失败。
  5. Docker逃逸
  6. Go 语言编译过程
  7. https://www.cs.cmu.edu/~dga/papers/cuckoo-conext2014.pdf 检验hash冲突
  8. Optimistic concurrency control 死锁 悲观锁 乐观锁 自旋锁
  9. WeCenter (最新版) 前台RCE漏洞 (2020-02-22)
  10. how2j SpringMVC学习心得