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 相关文章推荐
jquery cookie插件代码类
May 26 Javascript
jQuery中复合属性选择器用法实例
Dec 31 Javascript
jQuery实现表格文本框淡入更改值后淡出效果
Sep 27 Javascript
JavaScript浮点数及运算精度调整详解
Oct 21 Javascript
深入理解vue-loader如何使用
Jun 06 Javascript
node.js实现的装饰者模式示例
Sep 06 Javascript
微信小程序实现动态设置placeholder提示文字及按钮选中/取消状态的方法
Dec 14 Javascript
使用vue官方提供的模板vue-cli搭建一个helloWorld案例分析
Jan 16 Javascript
vue项目部署到Apache服务器中遇到的问题解决
Aug 24 Javascript
JS实现简单移动端鼠标拖拽
Jul 23 Javascript
mapboxgl实现带箭头轨迹线的代码
Jan 04 Javascript
详解uniapp的全局变量实现方式
Jan 11 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
第十五节--Zend引擎的发展
2006/11/16 PHP
PHP has encountered an Access Violation
2007/01/15 PHP
PHP实现的一致性哈希算法完整实例
2015/11/14 PHP
thinkPHP5.0框架验证码调用及点击图片刷新简单实现方法
2018/09/07 PHP
Laravel 连接(Join)示例
2019/10/16 PHP
javascript中的关于类型转换的性能优化
2010/12/14 Javascript
JavaScript Memoization 让函数也有记忆功能
2011/10/27 Javascript
给jQuery方法添加回调函数一款插件的应用
2013/01/21 Javascript
JS解决url传值出现中文乱码的另类办法
2013/04/08 Javascript
showModalDialog在谷歌浏览器下会返回Null的解决方法
2013/11/27 Javascript
EasyUI实现第二层弹出框的方法
2015/03/01 Javascript
String字符串截取的四种方式总结
2016/11/28 Javascript
详解微信小程序 页面跳转 传递参数
2016/12/08 Javascript
JavaScript制作简易计算器(不用eval)
2017/02/05 Javascript
react-router实现跳转传值的方法示例
2017/05/27 Javascript
JS中的Replace()传入函数时的用法详解
2017/09/11 Javascript
浅谈VueJS SSR 后端绘制内存泄漏的相关解决经验
2018/12/20 Javascript
[02:10]三分钟回顾完美世界城市挑战赛
2019/01/24 DOTA
[01:10:24]DOTA2-DPC中国联赛 正赛 VG vs Aster BO3 第一场 2月28日
2021/03/11 DOTA
Python实现基于权重的随机数2种方法
2015/04/28 Python
python中关于for循环的碎碎念
2017/06/30 Python
使用python的pandas库读取csv文件保存至mysql数据库
2018/08/20 Python
解决yum对python依赖版本问题
2019/07/05 Python
选择Python写网络爬虫的优势和理由
2019/07/07 Python
python中tkinter的应用:修改字体的实例讲解
2019/07/17 Python
利用python-pypcap抓取带VLAN标签的数据包方法
2019/07/23 Python
nginx搭建基于python的web环境的实现步骤
2020/01/03 Python
Django框架配置mysql数据库实现过程
2020/04/22 Python
Python-opencv实现红绿两色识别操作
2020/06/04 Python
S’well Bottle保温杯官网:绝缘不锈钢水瓶
2018/05/09 全球购物
艺术设计专业个人求职信
2013/09/21 职场文书
电厂厂长岗位职责
2014/01/02 职场文书
仓库管理员岗位职责
2014/03/19 职场文书
保护校园环境倡议书
2015/04/28 职场文书
redis的list数据类型相关命令介绍及使用
2022/01/18 Redis
python数字图像处理数据类型及颜色空间转换
2022/06/28 Python