原型模式


原型模式用于在创建对象时,通过共享某个对象原型的属性和方法,从而达到提高性能、降低内存占用、代码复用的效果。
  1. 示例一
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();

该函数创建实例时原型图如下:

  1. 示例二
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);

该函数创建实例时原型图如下:

  1. 示例三
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");
  1. 总结

    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设计模式之原型模式、发布订阅模式的更多相关文章

  1. 理解JavaScript设计模式与开发应用中发布-订阅模式的最终版代码

    最近拜读了曾探所著的<JavaScript设计模式与开发应用>一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线 ...

  2. js 设计模式:观察者和发布订阅模式

    总是把这两个当作同一个模式,但其实是不太一样的,现在重温一下. 观察者模式 观察者直接订阅目标,当目标触发事件时,通知观察者进行更新 简单实现 class Observer { constructor ...

  3. 阶段5 3.微服务项目【学成在线】_day05 消息中间件RabbitMQ_8.RabbitMQ研究-工作模式-发布订阅模式-生产者

    Publish/subscribe:发布订阅模式 发布订阅模式: 1.每个消费者监听自己的队列. 2.生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将 ...

  4. javascript设计模式学习之八_发布订阅(观察者)模式

    一.发布订阅模式定义 jQuery中的callbacks,defered,promise本质上就是发布订阅模式的实现.ES6的promise内部实现未开源,不了解具体机制 发布订阅模式又叫做观察者模式 ...

  5. JS设计模式(5)发布订阅模式

    什么是发布订阅模式(观察者模式)? 定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. 主要解决:一个对象状态改变给其他对象通知的问题,而且 ...

  6. 4.js模式-发布-订阅模式

    1. 发布-订阅模式 var observe = (function(){ var events = {}, listen, trigger, remmove; listen = function(k ...

  7. RabbitMQ六种队列模式-发布订阅模式

    前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅 [本文]RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主 ...

  8. 阶段5 3.微服务项目【学成在线】_day05 消息中间件RabbitMQ_9.RabbitMQ研究-工作模式-发布订阅模式-消费者

    消费者需要写两个消费者 定义邮件的类 复制以前的代码到邮件类里面进行修改 最上面 声明队列的名称和交换机的名称 监听修改为email 的队列的名称 手机短信接收端 复制一份email的接收端的代码 改 ...

  9. java设计模式之-观察者模式(发布-订阅模式)

    1.观察者模式定义  观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象. 这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己. 2.观察者模式结构 ...

  10. java 观察这模式(发布订阅模式)

    观察者设计模式定义了对象间的一种一对多的组合关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新. 发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息. 抽象 ...

随机推荐

  1. C#多线程---ReaderWriterLock实现线程同步

    一.简介 当我们需要对一个共享资源多次读取的时候,用前面Monitor的同步锁就没有必要了.因为同步锁每次只允许一个线程访问共享资源,其他线程都会阻塞. 此时,通过ReaderWriterLock类可 ...

  2. 【ArcEngine】AE连接SDE_For_SQLServer参数设置

    SDE for sqlserver直连的ArcEngine访问 Ae中的数据的连接实质还是采用服务连接的方式.连接代码如下: 1 public IWorkspace Getworkspace() 2 ...

  3. css - 全屏

    css - 全屏 heml和body元素的宽高 html与body都是块元素,但它俩比较特殊,宽高由如下定义: 1.默认的宽度=浏览器可视区域的宽度(不包含滚动条),可设置大于可视区域的宽度,但不会计 ...

  4. C++:继承

    共有继承(public),私有继承(private),保护继承(protected): 1.public继承: 基类成员类型 作为派生类成员 在派生类中是否可见 对派生类对象的可见性 public p ...

  5. go协程调度

    目录 前言 1. 线程池的缺陷 2.Goroutine 调度器 3.调度策略 3.1 队列轮转 3.2 系统调用 3.3 工作量窃取 4.GOMAXPROCS设置对性能的影响 参考 前言 Gorout ...

  6. 临时性备用 socks 巧(科)妙(学)上网,你懂的,不多解释

    最近 Shadowsock s 不稳定,极大的影响了工作效率.不过 ssh 还能连上自己的机器,所以掏出 ssh -D 满足自己 #!/usr/bin/env bash disable_proxy() ...

  7. volatile的基本原理

    volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以 ...

  8. C#新版本风格(NetCore)项目文件

    在VisualStudio中创建NetCore以上版本的项目,使用的都是新版本风格的项目文件. 和旧版本.NetFramework版本的项目文件区别: 双击项目可直接打开csproj文件进行编辑配置 ...

  9. 基本ServletWEB项目

    项目搭建 项目链接https://gitee.com/zhangjzm/smbms.git 前置知识,Servlet JSP 结构图 搭建maven web项目 1.搭建一个maven web项目 2 ...

  10. Mysql常用sql语句(7)- order by 对查询结果进行排序

    测试必备的Mysql常用sql语句系列 https://www.cnblogs.com/poloyy/category/1683347.html 前言 通过select出来的结果集是按表中的顺序来排序 ...