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();

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

image

示例二

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);

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

image

示例三

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 语言的原型特性进行相同属性的共享,从而达到降低内存占用、提高对象创建效率。

观察者模式 观察者模式用于模块、组件之间通讯,通过提供统一的模式进行事件订阅、事件发布。从而达到模块、组件之间解耦,提高代码的可维护性。 模块之间、组件之间通讯方式

image

模块之间、组件之间采用直接引用通讯方式 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 消息:
饭又来了

总结

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwwwfx.html