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 相关文章推荐
setTimeout和setInterval的区别你真的了解吗?
Mar 31 Javascript
深入理解JavaScript编程中的原型概念
Jun 25 Javascript
JavaScript阻止回车提交表单的方法
Dec 30 Javascript
JavaScript使ifram跨域相互访问及与PHP通信的实例
Mar 03 Javascript
JS中常用的正则表达式
Sep 29 Javascript
简单理解vue中el、template、replace元素
Oct 27 Javascript
基于vue2.0动态组件及render详解
Mar 17 Javascript
JavaScript中常见内置函数用法示例
May 14 Javascript
解决在vue项目中webpack打包后字体不生效的问题
Sep 01 Javascript
Vuex的热更替如何实现
Jun 05 Javascript
Vue使用v-viewer实现图片预览
Oct 21 Javascript
使用Ajax实现无刷新上传文件
Apr 12 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使用curl出现Expect:100-continue解决方法
2015/03/03 PHP
ucenter中词语过滤原理分析
2016/07/13 PHP
CodeIgniter框架验证码类库文件与用法示例
2017/03/18 PHP
PHP getDocNamespaces()函数讲解
2019/02/03 PHP
PHP基础之输出缓冲区基本概念、原理分析
2019/06/19 PHP
一种JavaScript的设计模式
2006/11/22 Javascript
asp 取文本框名称代码
2008/12/02 Javascript
基于jQuery选择器的整理集合
2013/04/26 Javascript
JS防止用户多次提交的简单代码
2013/08/01 Javascript
jquery实现用户打分评分特效
2015/05/28 Javascript
JS正则表达式之非捕获分组用法实例分析
2016/12/28 Javascript
bootstrap滚动监控器使用方法解析
2017/01/13 Javascript
Base64(二进制)图片编码解析及在各种浏览器的兼容性处理
2017/02/09 Javascript
vue2.0多条件搜索组件使用详解
2020/03/26 Javascript
微信小程序实现下拉刷新和轮播图效果
2017/11/21 Javascript
node简单实现一个更改头像功能的示例
2017/12/29 Javascript
js getBoundingClientRect使用方法详解
2019/07/17 Javascript
uniapp,微信小程序中使用 MQTT的问题
2020/07/11 Javascript
Vue+axios封装请求实现前后端分离
2020/10/23 Javascript
[37:23]DOTA2上海特级锦标赛主赛事日 - 3 胜者组第二轮#2Secret VS EG第二局
2016/03/04 DOTA
Python实现简单的四则运算计算器
2016/11/02 Python
TensorFlow实现MLP多层感知机模型
2018/03/09 Python
python搭建服务器实现两个Android客户端间收发消息
2018/04/12 Python
十个Python练手的实战项目,学会这些Python就基本没问题了(推荐)
2019/04/26 Python
django序列化时使用外键的真实值操作
2020/07/15 Python
Python 创建TCP服务器的方法
2020/07/28 Python
纯CSS3代码实现switch滑动开关按钮效果
2016/08/30 HTML / CSS
HTML5计时器小例子
2013/10/15 HTML / CSS
迷你分体式空调:SoGoodToBuy
2018/08/07 全球购物
不同浏览器创建XMLHttpRequest方法有什么不同
2014/11/17 面试题
党的群众路线教育实践活动动员会主持词
2014/03/20 职场文书
助人为乐模范事迹材料
2014/06/02 职场文书
亲子运动会的活动方案
2014/08/17 职场文书
先进教师个人事迹材料
2014/12/15 职场文书
javascript函数式编程基础
2021/09/15 Javascript
如何Python使用re模块实现okenizer
2022/04/30 Python