Javascript设计模式之原型模式、发布订阅模式
原型模式
原型模式用于在创建对象时,通过共享某个对象原型的属性和方法,从而达到提高性能、降低内存占用、代码复用的效果。
- 示例一
function Person(name) {
this.name = name;
this.config = {
a: "1",
b: "2",
};
this.hello = function () {
console.info("hello");
};
}
假如需要通过以上代码创建 100 个实例,那么将需要创建 100 个 config、100 个 hello,而这两个东西在每个实例里面是完全一样的。
因此我们可以通过提取公共代码的方式进行油优化。
const config = {
a: "1",
b: "2",
};
const hello = function () {
console.info("hello");
};
function Person(name) {
this.name = name;
this.config = config;
this.hello = hello
}
这样的方式使得无论创建多少个Person对象都只需要创建一个config、一个hello。 但是仍然污染全局变量、config被误修改、Person和其他代码耦合大、不易于代码扩展维护等问题。
因此可以通过原型的方式进行优化。
function Person() {}
var p = new Person();
该函数创建实例时原型图如下:
- 示例二
function Person(name) {
this.name = name;
this.config = {
a: "1",
b: "2",
};
this.hello = function () {
console.info("hello");
};
}
//此方式会重写prototype,造成constructor丢失,变为Object()。
//可以使用Person.prototype.xx=yy的方式写,或者重新指定Person.prototype.constructor=Person
Person.prototype = {
version: 1.0,
say: function (arg) {
console.info(`${this.name} say ${arg}`);
},
constructor: Person,
};
var p1 = new Person("p1");
var p2 = new Person("p2");
console.info(p1.config == p2.config); //false
console.info(p1.hello == p2.hello); //false
console.info(p1.say === p2.say); //true
p1.say("qq");
p2.say("qq");
console.info(p1.version === p2.version); //true
console.info(p1.version);
该函数创建实例时原型图如下:
- 示例三
function Person(name) {
this.name = name;
this.config = {
a: "1",
b: "2",
};
this.hello = function () {
console.info("hello");
};
}
//此方式会重写prototype,造成constructor丢失,变为Object()
Person.prototype = {
version: 1.0,
say: function (arg) {
console.info(`${this.name} say ${arg}`);
},
};
function PersonA(name) {
Person.call(this, name);
}
PersonA.prototype = Person.prototype;
function PersonB(name) {
Person.call(this, name);
}
PersonB.prototype = Person.prototype;
var pA = new PersonA("pa");
var pB = new PersonB("pb");
console.info(pA.config == pB.config); //false 内部属性比较
console.info(pA.hello == pB.hello); //false 内部属性比较
console.info(pA.say === pB.say); //true 原型方法共享
pA.say("qq");
pB.say("qq");
console.info(pA.version === pB.version); //true 原型属性共享
console.info(pA.version); //1.0
Person.prototype.version = 2.0; //修改原型共享属性
console.info(pB.version); //2.0
console.info(new Person().version); //2.0
//修改原型共享方法
PersonB.prototype.say = function (arg) {
console.info(`v2--- ${this.name} say ${arg}`);
};
pB.say("qq");
new Person("Person").say("ww");
总结
js 在创建对象比较消耗内存、耗时长,可以通过减少内部属性创建的方式降低内存占用。
而原型模式就是使用 javascript 语言的原型特性进行相同属性的共享,从而达到降低内存占用、提高对象创建效率。
观察者模式
观察者模式用于模块、组件之间通讯,通过提供统一的模式进行事件订阅、事件发布。从而达到模块、组件之间解耦,提高代码的可维护性。
模块之间、组件之间通讯方式
模块之间、组件之间采用直接引用通讯方式
const moduleA = {
say: function (msg) {
console.info("A say " + msg);
},
letBrun: function () {
//直接引用了moduleB
moduleB.run();
},
};
const moduleB = {
run: function () {
console.info("B run ");
},
letAsay: function () {
//直接引用了moduleA
moduleA.say("hello");
},
};
moduleA.letBrun(); //B Run
moduleB.letAsay(); //A say hello
模块之间、组件之间采用父组件通讯方式
const moduleA = {
say: function (msg) {
console.info("A say " + msg);
},
};
const moduleB = {
run: function () {
console.info("B run ");
},
};
const parentModule = {
moduleA,
moduleB,
letBrun: function () {
this.moduleB.run();
},
letAsay: function () {
this.moduleA.say("hello");
},
};
parentModule.letBrun(); //B Run
parentModule.letAsay(); //A say hello
事件模块实现通讯
function Emitter() {
this.events = {};
this.res_oldAction = {}
this.res_action_events = {}
}
//订阅资源
Emitter.prototype.subscribe = function (res, action, fn) {
if(!this.res_oldAction[res.name]){
this.res_oldAction[res.name] = res[action]
res[action] = (data) => {
this.res_oldAction[res.name](data)
const fns = this.res_action_events[res.name].action;
for (let i = 0; i < fns.length; i++) {
fns[i](data);
}
}
}
if(!this.res_action_events[res.name]){
this.res_action_events[res.name] = {}
}
if(!this.res_action_events[res.name][action]){
this.res_action_events[res.name][action] = []
}
this.res_action_events[res.name].action.push(fn)
}
//取消订阅资源
Emitter.prototype.unsubscribe = function (res, action, fn) {
const fns = this.res_action_events[res.name].action;
for (let i = 0; i < fns.length; i++) {
if (fns[i] === fn) {
fns.splice(i, 1);
i--;
}
}
}
Emitter.prototype.on = function (name, fn) {
if (!this.events[name]) {
this.events[name] = [];
}
this.events[name].push(fn);
};
Emitter.prototype.remove = function (name, fn) {
if (!this.events[name]) {
return;
}
const fns = this.events[name];
for (let i = 0; i < fns.length; i++) {
if (fns[i] === fn) {
fns.splice(i, 1);
i--;
}
}
};
Emitter.prototype.fire = function (name, data) {
if (!this.events[name]) {
return;
}
const fns = this.events[name];
for (let i = 0; i < fns.length; i++) {
fns[i](data);
}
};
const emitter = new Emitter();
//模块A中注册事件
const methodA = (data) => {
console.info("模块A接受到food消息:");
console.info(data);
};
emitter.on("food", methodA);
//模块B中注册事件
const methodB = (data) => {
console.info("模块B接受到food消息:");
console.info(data);
};
emitter.on("food", methodB);
//模块C中触发事件
emitter.fire("food", "饭来了");
//模块B中移除事件
emitter.remove("food", methodB);
//模块C中再次触发事件
emitter.fire("food", "饭又来了");
执行结果如下:
模块 A 接受到 food 消息:
饭来了
模块 B 接受到 food 消息:
饭来了
模块 A 接受到 food 消息:
饭又来了
总结
js 组件模块的通讯方式一般分为3种(直接通讯、通过父组件通讯、通过事件模块通讯)。观察者模式用于模块、组件之间通讯,通过提供统一的模式进行事件订阅、事件发布,从而达到模块、组件之间解耦,提高代码的可维护性
Javascript设计模式之原型模式、发布订阅模式的更多相关文章
- 理解JavaScript设计模式与开发应用中发布-订阅模式的最终版代码
最近拜读了曾探所著的<JavaScript设计模式与开发应用>一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线 ...
- js 设计模式:观察者和发布订阅模式
总是把这两个当作同一个模式,但其实是不太一样的,现在重温一下. 观察者模式 观察者直接订阅目标,当目标触发事件时,通知观察者进行更新 简单实现 class Observer { constructor ...
- 阶段5 3.微服务项目【学成在线】_day05 消息中间件RabbitMQ_8.RabbitMQ研究-工作模式-发布订阅模式-生产者
Publish/subscribe:发布订阅模式 发布订阅模式: 1.每个消费者监听自己的队列. 2.生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将 ...
- javascript设计模式学习之八_发布订阅(观察者)模式
一.发布订阅模式定义 jQuery中的callbacks,defered,promise本质上就是发布订阅模式的实现.ES6的promise内部实现未开源,不了解具体机制 发布订阅模式又叫做观察者模式 ...
- JS设计模式(5)发布订阅模式
什么是发布订阅模式(观察者模式)? 定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. 主要解决:一个对象状态改变给其他对象通知的问题,而且 ...
- 4.js模式-发布-订阅模式
1. 发布-订阅模式 var observe = (function(){ var events = {}, listen, trigger, remmove; listen = function(k ...
- RabbitMQ六种队列模式-发布订阅模式
前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅 [本文]RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主 ...
- 阶段5 3.微服务项目【学成在线】_day05 消息中间件RabbitMQ_9.RabbitMQ研究-工作模式-发布订阅模式-消费者
消费者需要写两个消费者 定义邮件的类 复制以前的代码到邮件类里面进行修改 最上面 声明队列的名称和交换机的名称 监听修改为email 的队列的名称 手机短信接收端 复制一份email的接收端的代码 改 ...
- java设计模式之-观察者模式(发布-订阅模式)
1.观察者模式定义 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象. 这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己. 2.观察者模式结构 ...
- java 观察这模式(发布订阅模式)
观察者设计模式定义了对象间的一种一对多的组合关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新. 发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息. 抽象 ...
随机推荐
- wpf 实现印章,公章效果
能写一些特定外观的控件,是一个做界面开发的程序员的基础技能.基本上,不管你是做web,QT,MFC,Winform,WPF等等,如果自己看到一个比较好看的有趣的效果,能大致推断出它的实现方式并照猫画虎 ...
- C++11 shared_ptr(智能指针)详解
要确保用 new 动态分配的内存空间在程序的各条执行路径都能被释放是一件麻烦的事情.C++ 11 模板库的 <memory> 头文件中定义的智能指针,即 shared _ptr 模板,就是 ...
- Flink的CheckPoint
Checkpoint checkpoint是Flink容错的核心机制.它可以定期的将各个Operator处理的数据进行快照存储(Snapshot). 如果Flink程序出现宕机,可以重新从这些快照中恢 ...
- 修改Windows7系统默认软件安装目录
Windows7系统默认软件安装目录都在C盘Program Files文件夹有时候我们需要把软件安装到其他地方,如果每次安装的时候都要重新选择一次十分麻烦,下面Windows7之家教你修改软件默认安装 ...
- MySQL案例:一次单核CPU占用过高问题的处理
客户现场反馈,top的检查结果中,一个CPU的占用一直是100%.实际上现场有4个CPU,而且这个服务器是mysql专属服务器. 我的第一反应是io_thread一类的参数设置有问题,检查以后发现re ...
- RHCA-openstack学习部署笔记-CL210
笔记说明:目前考试是基于RHELOSP13(32G)来进行环境部署,引入了容器,而学习是基于RHELOSP6来安装部署的,基于Openstack. 讨论:openstack.虚拟化和云计算的关系以及区 ...
- 浅析Is-a,Has-a与like-a
在面向对象的设计领域里,有很多设计思路,主要有三种:is-a.has-a.like-a. 这三种在java的类.接口.抽象类中很多体现,下面简述一下其定义. 1.Is-a(继承关系) is-a,顾名思 ...
- RabbitMQ核心知识总结!
本文已经收录到github仓库,此仓库用于分享Java相关知识总结,包括Java基础.MySQL.Spring Boot.MyBatis.Redis.RabbitMQ.计算机网络.数据结构与算法等等, ...
- rune和byte在处理字符/字符串中的应用.
rune和byte在处理字符/字符串中的应用. 定义: rune是int32的别名,-2147483648->2147483647,常用来表示UNICODE字符集,可以用来处理包含中文/非中文的 ...
- HDU2063 过山车(二分匹配)
过山车 HDU - 2063 RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了.可是,过山车的每一排只有两个座位,而且还有条不成文的规矩,就是每个女生必须找个个男生做part ...