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

一篇文章图文并茂地带你轻松学完 JavaScript 设计模式(二)的更多相关文章

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

    JavaScript 设计模式(一) 本文需要读者至少拥有基础的 ES6 知识,包括 Proxy, Reflect 以及 Generator 函数等. 至于这次为什么分了两篇文章,有损传统以及标题的正 ...

  2. 一篇文章图文并茂地带你轻松学完 JavaScript 原型和原型链

    JavaScript 原型和原型链 在阅读本文章之前,已经默认你了解了基础的 JavaScript 语法知识,基础的 ES6 语法知识 . 本篇文章旨在为 JavaScript继承 打下基础 原型 在 ...

  3. 一篇文章图文并茂地带你轻松学完 JavaScript 继承

    JavaScript 继承 在阅读本文章之前,已经默认你了解了基础的 JavaScript 语法知识,基础的 ES6 语法知识 . 继承种类 简单的继承种类可以分为 构造函数继承 原型链继承 clas ...

  4. 一篇文章图文并茂地带你轻松学完 JavaScript 事件循环机制(event loop)

    JavaScript 事件循环机制 (event loop) 本篇文章已经默认你有了基础的 ES6 和 javascript语法 知识. 本篇文章比较细致,如果已经对同步异步,单线程等概念比较熟悉的读 ...

  5. 一篇文章图文并茂地带你轻松学完 JavaScript 闭包

    JavaScript 闭包 为了更好地理解 JavaScript 闭包,笔者将先从 JavaScript 执行上下文以及 JavaScript 作用域开始写起,如果读者对这方面已经了解了,可以直接跳过 ...

  6. 一篇文章图文并茂地带你轻松实践 HTML5 history api

    HTML5 history api 前言 由于笔者在网络上没有找到比较好的关于 history api 的实践案例,有的案例过于杂乱,没有重点,有些案例只是告诉读者 api 是什么,却没告诉怎么用,本 ...

  7. 一篇文章图文并茂地带你轻松学会 HTML5 storage

    html5 storage api localStorage 和 sessionStorage 是 html5 新增的用来存储数据的对象,他们让我们可以以键值对的形式存储信息. 为什么要有 stora ...

  8. 一篇文章让你快速入门 学懂Shell脚本

    Shell脚本,就是利用Shell的命令解释的功能,对一个纯文本的文件进行解析,然后执行这些功能,也可以说Shell脚本就是一系列命令的集合. Shell可以直接使用在win/Unix/Linux上面 ...

  9. 学完JavaScript基础有感

    紧接上一篇回来了,这几天一直学js,会不自觉的和其他的编程语言联系在一起,在没有学jQuery之前,结合我所学的c,java,数据结构,数据库以及部分html感觉到JavaScript里面又很多相似的 ...

随机推荐

  1. Android之Xposed

    基础书籍推荐:1.疯狂JAVA讲义:2.疯狂安卓讲义: 逆向分析必须知道他的原理,不然只会用工具,那就直接GG. 谷歌的镜像网站:https://developers.google.com/andro ...

  2. 微软官网下载win10离线介质

    1.打开google浏览器 2.搜索win10官网下载或者直接输入网址https://www.microsoft.com/zh-cn/software-download/windows10 3.按F1 ...

  3. 开篇:免费开源的趣讲 ZooKeeper 教程(连载)

    本文作者:HelloGitHub-老荀 一.起因 良好的开端,是成功的一半. 我是作者老荀,一个普通的程序员,没有 985 和 211 的背景,也从没在大厂工作过.仅仅是喜欢研究技术,一直想做一个讲解 ...

  4. 02--Docker配置阿里云镜像加速器

    1.登录阿里云控制台,在产品与服务中收索 "容器镜像服务" 2.点击镜像加速器,CentOS 3.在路径 /etc/docker/daemon.json 下配置加速器地址 4.重新 ...

  5. zabbix-server安装部署配置

    zabbix-server安装部署配置 zabbixLinux安装部署安装脚本 1 一步一步部署 1.1 安装zabbix仓库源 这里安装阿里的zabbix仓库地址 选用zabbix版本3.4 rpm ...

  6. MYSQL(将数据加载到表中)

    1. 创建和选择数据库 mysql> CREATE DATABASE menagerie; mysql> USE menagerie Database changed 2. 创建表 mys ...

  7. CSS不用背景图片实现优惠券样式反圆角,凹圆角,反向半圆角,并且背景渐变

    日常开发过程中,特别是商城相关应用开发过程中,时常会遇到花里胡哨的设计图,比如优惠券样式,上图: 实现思路如下:     1.先写一个外容器,实现背景色渐变: Html: 1 <div clas ...

  8. 03. struts2中Action配置的各项默认值

    Action中的各项默认值 Action各项配置 <action name="helloworld" class="com.liuyong666.action.He ...

  9. Linux监控内核SNMP计数器

    nstat命令和rtacct命令是一个简单的监视内核的SNMP计数器和网络接口状态的实用工具. 语法 nstat/rtacct (选项) 选项 -h:显示帮助信息: -V:显示指令版本信息: -z:显 ...

  10. Flutter GetX使用---简洁的魅力!

    前言 使用Bloc的时候,有一个让我至今为止十分在意的问题,无法真正的跨页面交互!在反复的查阅官方文档后,使用一个全局Bloc的方式,实现了"伪"跨页面交互,详细可查看:flutt ...