原型模式


原型模式用于在创建对象时,通过共享某个对象原型的属性和方法,从而达到提高性能、降低内存占用、代码复用的效果。
  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. 【js】--获取开始时间 和 截止时间中间的所有时间

    1.工具函数  将[中国标准时间] 转换成 [年月日 时分秒] /* * timeStamp: 标准时间 例: 'Tue Sep 22 2020 00:00:00 GMT+0800 (中国标准时间)' ...

  2. Android开发,缺少权限导致无法修改原文件,获取所有文件访问权限的方法

    在Android 11开发中,app会遇到使用绝对路径无法打开某文件的情况(文件存在根目录下,获取到的路径为:/storage/emulated/0/XXX.txt),而使用相对路径打开文件后(获取到 ...

  3. tree命令出现乱码

    alias tree='tree --charset ASCII'就可以了

  4. ES6扩展——数组扩展

    1.结合扩展运算符使用.通过扩展运算符,在调用函数的时候,把一个数组展开,然后作为这个函数的参数 //结合扩展运算符使用 function foo(a,b,c){ console.log(a); // ...

  5. 机器学习基本概念:batch_size、epoch、 iteration

    batch_size 单次训练用的样本数,通常为2^N,如32.64.128... 相对于正常数据集,如果过小,训练数据就收敛困难:过大,虽然相对处理速度加快,但所需内存容量增加. 使用中需要根据计算 ...

  6. 【Spring 5.x】学习笔记汇总

    Spring 工厂 工厂设计模式.第一个Spring程序细节分析.整合日志框架 注入详解 - Set注入(JDK内置类型,用户自定义类型).构造注入(重载) 反转控制与依赖注入.Spring工厂创建复 ...

  7. Oracle环境配置之山路十八弯

    Oracle数据库的安装 背景: 因为疫情原因,只能在家上网课,学习Oracle的时候需要安装数据库,但是!! 安装的时候出现了报错: 无法检查指定的位置是否位于 CFS 上. 出来这个基本无解,这个 ...

  8. openswan中DH算法说明

    Author       : Email         : vip_13031075266@163.com Date          : 2021.01.11 Copyright : 未经同意不得 ...

  9. Devexpress主题/皮肤

    如何在C#中使用DevExpress皮肤管理器.步骤1: 单击 新建项目,然后选择左侧的Visual C#,然后 视窗 ,然后选择 Windows窗体应用程序.将您的项目命名为" SkinD ...

  10. 密码学系列之:海绵函数sponge function

    目录 简介 海绵函数的结构 海绵函数的应用 简介 海绵函数sponge function是密码学中使用的一种函数,它接收一定长度的输入,然后输出一定长度的输出,中间包含了有限个内部状态. 因为海绵函数 ...