Javascript设计模式之原型模式详细


Posted in Javascript onOctober 05, 2021

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

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

Javascript设计模式之原型模式详细

示例二

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

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

Javascript设计模式之原型模式详细

示例三

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

2、观察者模式

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

模块之间、组件之间通讯方式

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玩一玩WSH吧
Feb 23 Javascript
用jscript实现新建和保存一个word文档
Jun 15 Javascript
JS 学习笔记 防止发生命名冲突
Jul 30 Javascript
JavaScript中九种常用排序算法
Sep 02 Javascript
js判断子窗体是否关闭的方法
Aug 11 Javascript
跟我学习javascript的undefined与null
Nov 17 Javascript
详解JavaScript基于面向对象之继承
Dec 13 Javascript
jquery中object对象循环遍历的方法
Dec 18 Javascript
Javascript中引用类型传递的知识点小结
Mar 06 Javascript
Angular2.js实现表单验证详解
Jun 23 Javascript
JS操作Fckeditor的一些常用方法(获取、插入等)
Feb 19 Javascript
详解Vue.js 可拖放文本框组件的使用
Mar 03 Vue.js
JS数组方法some、every和find的使用详情
8个JS的reduce使用实例和reduce操作方式
Oct 05 #Javascript
JS 4个超级实用的小技巧 提升开发效率
Oct 05 #Javascript
JavaScript实现简单拖拽效果
Sep 15 #Javascript
一小时迅速入门Mybatis之bind与多数据源支持 Java API
Sep 15 #Javascript
Javascript之datagrid查询详解
Sep 15 #Javascript
Js类的构建与继承案例详解
Sep 15 #Javascript
You might like
php输出表格的实现代码(修正版)
2010/12/29 PHP
PHP发明人谈MVC和网站设计架构 貌似他不支持php用mvc
2011/06/04 PHP
php生成excel列序号代码实例
2013/12/24 PHP
php实现获取文章内容第一张图片的方法
2014/11/04 PHP
php 截取GBK文档某个位置开始的n个字符方法
2017/03/08 PHP
laravel中的一些简单实用功能
2018/11/03 PHP
Laravel 数据库加密及数据库表前缀配置方法
2019/10/10 PHP
基于jQuery的淡入淡出可自动切换的幻灯插件
2010/08/24 Javascript
JavaScript 字符串处理函数使用小结
2010/12/02 Javascript
javascript判断ie浏览器6/7版本加载不同样式表的实现代码
2011/12/26 Javascript
jQuery的context属性用法实例
2014/12/27 Javascript
jQuery使用hide方法隐藏指定元素class样式用法实例
2015/03/30 Javascript
jquery实现的仿天猫侧导航tab切换效果
2015/08/24 Javascript
js中setTimeout的妙用--防止循环超时
2017/03/06 Javascript
jQuery插件HighCharts绘制2D柱状图、折线图的组合双轴图效果示例【附demo源码下载】
2017/03/09 Javascript
Vue+Element使用富文本编辑器的示例代码
2017/08/14 Javascript
vue-cli 目录结构详细讲解总结
2019/01/15 Javascript
js实现适配移动端的拖动效果
2020/01/13 Javascript
微信小程序scroll-view的滚动条设置实现
2020/03/02 Javascript
小程序选项卡以及swiper套用(跨页面)
2020/06/19 Javascript
Javascript如何递归遍历本地文件夹
2020/08/06 Javascript
Vue3 实现双盒子定位Overlay的示例
2020/12/22 Vue.js
[51:05]DOTA2上海特级锦标赛主赛事日 - 5 败者组决赛Liquid VS EG第一局
2016/03/06 DOTA
Python高级应用实例对比:高效计算大文件中的最长行的长度
2014/06/08 Python
python实现分析apache和nginx日志文件并输出访客ip列表的方法
2015/04/04 Python
在Django中使用Sitemap的方法讲解
2015/07/22 Python
PyTorch的深度学习入门教程之构建神经网络
2019/06/27 Python
如何更优雅地写python代码
2019/07/02 Python
Keras 在fit_generator训练方式中加入图像random_crop操作
2020/07/03 Python
详解HTML5中的标签
2015/06/19 HTML / CSS
iKRIX意大利网上商店:男女豪华服装和配件
2019/10/09 全球购物
决定成败的关键——创业计划书
2014/01/24 职场文书
网站客服岗位职责
2014/04/05 职场文书
爱我中华演讲稿
2014/05/20 职场文书
SpringBoot集成Redis的思路详解
2021/10/16 Redis
MySQL中一条update语句是如何执行的
2022/03/16 MySQL