一篇文章图文并茂地带你轻松学完 JavaScript 设计模式(二)
JavaScript 设计模式(二)
本篇文章是 JavaScript 设计模式的第二篇文章,如果没有看过我上篇文章的读者,可以先看完 上篇文章 后再看这篇文章,当然两篇文章并没有过多的依赖性。
5. 代理模式
代理模式提供了对目标对象的另一种访问机制。
在 vue3 还没出来之前,我猜过可能会使用 proxy 取代 defineProperty ,结果也被验证了,毕竟 proxy 比 defineProperty 支持更多的拦截机制,可以对数组的方法进行拦截。
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 设计模式是程序设计中很重要的一个环节,在了解了各种设计模式之后,可以在遇到实际项目的时候,预先选择好一个好的设计模式用于开发,提高项目的可扩展性,也有助于我们理解源码。
一篇文章图文并茂地带你轻松学完 JavaScript 设计模式(二)的更多相关文章
- 一篇文章图文并茂地带你轻松学完 JavaScript 设计模式(一)
JavaScript 设计模式(一) 本文需要读者至少拥有基础的 ES6 知识,包括 Proxy, Reflect 以及 Generator 函数等. 至于这次为什么分了两篇文章,有损传统以及标题的正 ...
- 一篇文章图文并茂地带你轻松学完 JavaScript 原型和原型链
JavaScript 原型和原型链 在阅读本文章之前,已经默认你了解了基础的 JavaScript 语法知识,基础的 ES6 语法知识 . 本篇文章旨在为 JavaScript继承 打下基础 原型 在 ...
- 一篇文章图文并茂地带你轻松学完 JavaScript 继承
JavaScript 继承 在阅读本文章之前,已经默认你了解了基础的 JavaScript 语法知识,基础的 ES6 语法知识 . 继承种类 简单的继承种类可以分为 构造函数继承 原型链继承 clas ...
- 一篇文章图文并茂地带你轻松学完 JavaScript 事件循环机制(event loop)
JavaScript 事件循环机制 (event loop) 本篇文章已经默认你有了基础的 ES6 和 javascript语法 知识. 本篇文章比较细致,如果已经对同步异步,单线程等概念比较熟悉的读 ...
- 一篇文章图文并茂地带你轻松学完 JavaScript 闭包
JavaScript 闭包 为了更好地理解 JavaScript 闭包,笔者将先从 JavaScript 执行上下文以及 JavaScript 作用域开始写起,如果读者对这方面已经了解了,可以直接跳过 ...
- 一篇文章图文并茂地带你轻松实践 HTML5 history api
HTML5 history api 前言 由于笔者在网络上没有找到比较好的关于 history api 的实践案例,有的案例过于杂乱,没有重点,有些案例只是告诉读者 api 是什么,却没告诉怎么用,本 ...
- 一篇文章图文并茂地带你轻松学会 HTML5 storage
html5 storage api localStorage 和 sessionStorage 是 html5 新增的用来存储数据的对象,他们让我们可以以键值对的形式存储信息. 为什么要有 stora ...
- 一篇文章让你快速入门 学懂Shell脚本
Shell脚本,就是利用Shell的命令解释的功能,对一个纯文本的文件进行解析,然后执行这些功能,也可以说Shell脚本就是一系列命令的集合. Shell可以直接使用在win/Unix/Linux上面 ...
- 学完JavaScript基础有感
紧接上一篇回来了,这几天一直学js,会不自觉的和其他的编程语言联系在一起,在没有学jQuery之前,结合我所学的c,java,数据结构,数据库以及部分html感觉到JavaScript里面又很多相似的 ...
随机推荐
- 软碟通制作win10镜像,无法打开install.wim的问题
打开软碟通,单击左上角"文件"→"打开",选择.iso文件的存放目录,再选择.iso映像文件打开,即可看到映像文件全部加载到UltraISO了,如下图. 将 ...
- 【linux】系统编程-6-POSIX标准下的信号量与互斥锁
目录 前言 8. POSIX信号量 8.1 概念 8.2 POSIX无名信号量 8.3 POSIX有名信号量 8.4 POPSIX信号量与system V信号量的区别 9. POSIX互斥锁 9.1 ...
- buuctf刷题之旅—web—WarmUp
启动靶机 查看源码发现source.php 代码审计,发现hint.php文件 查看hint.php文件(http://7ab330c8-616e-4fc3-9caa-99d9dd66e191.nod ...
- Redis 实战 —— 03. Redis 简单实践 - Web应用
需求 功能: P23 登录 cookie 购物车 cookie 缓存生成的网页 缓存数据库行 分析网页访问记录 高层次角度下的 Web 应用 P23 从高层次的角度来看, Web 应用就是通过 HTT ...
- 计算机之路 -MySQL 初学
照着电脑学了一天终于把MySQL装上了. 明天打算重新装一次 然后再自己记录一下步骤
- Navicat linux 官方最新版安装破解
我们直接去官网下载linux版navicat 下载好之后执行命令打开软件 chmod +x navicat15-premium-cs.AppImage ./navicat15-premium-cs.A ...
- Docker 建站小记
一,前言 Docker 建站小记,我使用了四个镜像来搭建:nginx,certbot,mysql,gradle.欢迎访问:https://www.zzk0.top 这个网页是从 github 上找的个 ...
- 前端知识(二)03-Webpack-谷粒学院
目录 一.什么是Webpack 二.Webpack安装 1.全局安装 2.安装后查看版本号 三.创建项目 1.初始化项目 2.创建src文件夹 3.src下创建common.js 4.src下创建ut ...
- 【.NET 与树莓派】矩阵按键
欢迎收看火星卫视,本期节目咱们严重探讨一下矩阵按键. 所谓矩阵按键,就是一个小键盘(其实一块PCB板),上面有几个 Key(开关),你不按下去的时候,电路是断开的,你按下去电路就会接通.至于说有多少个 ...
- 《awk中文手册》-本人参考官方手册翻译
01. 简介 AWK是一个文本(面向行和列)处理工具,同时它也是一门脚本语言. AWK其名称得自于它的创始人 Alfred Aho .Peter Weinberger 和 Brian Kernigha ...