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 相关文章推荐
Javascript 判断 object 的特定类转载
Feb 01 Javascript
javascript十个最常用的自定义函数(中文版)
Sep 07 Javascript
JavaScript操纵窗口的方法小结
Jun 28 Javascript
javascript数组操作(创建、元素删除、数组的拷贝)
Apr 07 Javascript
构造函数+原型模式构造js自定义对象(最通用)
May 12 Javascript
Jquery跳到页面指定位置的方法
May 12 Javascript
jQuery知识点整理
Jan 30 Javascript
Bootstrap富文本组件wysiwyg数据保存到mysql的方法
May 09 Javascript
3kb jQuery代码搞定各种树形选择的实现方法
Jun 10 Javascript
js实现3d悬浮效果
Feb 16 Javascript
p5.js入门教程之图片加载
Mar 20 Javascript
微信小程序利用canvas 绘制幸运大转盘功能
Jul 06 Javascript
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面向对象编程快速入门
2006/12/14 PHP
修改了一个很不错的php验证码(支持中文)
2007/02/14 PHP
用PHP连接MySQL代码的参数说明
2008/06/07 PHP
php+xml结合Ajax实现点赞功能完整实例
2015/01/30 PHP
PHP使用curl模拟post上传及接收文件的方法
2016/03/04 PHP
注意!PHP 7中不要做的10件事
2016/09/18 PHP
php源码之将图片转化为data/base64数据流实例详解
2016/11/27 PHP
详解关于php的xdebug配置(编辑器vscode)
2019/01/29 PHP
PHP如何解决微信文章图片防盗链
2020/12/09 PHP
Maps Javascript
2007/01/22 Javascript
FireFox JavaScript全局Event对象
2009/06/14 Javascript
js用Date对象处理时间实现思路及代码
2013/01/31 Javascript
使用jquery获取网页中图片高度的两种方法
2013/09/26 Javascript
Jquery Ajax方法传值到action的方法
2014/05/11 Javascript
IE下使用jQuery重置iframe地址时内存泄露问题解决办法
2015/02/05 Javascript
Angular 4依赖注入学习教程之FactoryProvider配置依赖对象(五)
2017/06/04 Javascript
Vue2.0实现购物车功能
2017/06/05 Javascript
JavaScript 中的12种循环遍历方法【总结】
2018/05/31 Javascript
深入浅析Vue中的Prop
2018/06/10 Javascript
微信小程序引入VANT组件的方法步骤
2019/09/19 Javascript
微信小程序canvas截取任意形状的实现代码
2020/01/13 Javascript
Vue CLI4 Vue.config.js标准配置(最全注释)
2020/06/05 Javascript
Electron 打包问题:electron-builder 下载各种依赖出错(推荐)
2020/07/09 Javascript
vue使用echarts图表自适应的几种解决方案
2020/12/04 Vue.js
[03:31]DOTA2英雄基础教程 大地之灵
2013/12/17 DOTA
在Python中处理日期和时间的基本知识点整理汇总
2015/05/22 Python
python数组过滤实现方法
2015/07/27 Python
Python 爬虫图片简单实现
2017/06/01 Python
python实现内存监控系统
2021/03/07 Python
jupyter notebook快速入门及使用详解
2020/11/13 Python
Python导入父文件夹中模块并读取当前文件夹内的资源
2020/11/19 Python
Canvas 文本转粒子效果的实现代码
2019/02/14 HTML / CSS
FOREO官方网站:LUNA露娜洁面仪
2016/11/28 全球购物
学校大课间活动方案
2014/01/30 职场文书
村党的群众路线教育实践活动工作总结
2014/10/25 职场文书
2016教师节问候语
2015/11/10 职场文书