JavaScript --- [学习笔记]观察者模式 理解对象 工厂模式 构造函数模式

说明

  • 本系列(JS基础梳理)为后面TCP的模拟实现做准备
  • 本篇的主要内容: 观察者模式、工厂模式、构造函数模式 和 对对象的理解

1. 观察者模式

  • 参考JavaScript设计模式

1.1 消息注册方法

“将订阅者注册的消息推入到消息队列中”

[算法思路] :

  1. 在推入到消息队列时,如果此消息不存在则应该创建一个该消息类型并将该消息放入消息队列中
  2. 如果此消息存在则应该将消息执行方法推入该消息对应的执行方法队列中(保证多个模块注册一则消息时能顺利执行)
regist: function(type, fn) {// 如果消息不存在则应该创建一个该消息类型if(typeof __message[type] === 'undefined') {// 将动作推入到该消息对应的动作执行队列中__message[type] = [fn];// 如果此消息存在} else {// 将动作方法推入该消息对应的动作执行序列中__message[type].push(fn);}
}

1.2 发布消息方法

“对于发布消息方法,其功能是当观察者发布一个消息时将所有订阅者的消息一次执行”

fire: function(type, args) {// 如果该消息没有被注册,则返回if(!__message[type])return;// 定义消息信息var events = {type: type,args: args || {}},i = 0,len = __message[type].length;// 遍历消息动作for(; i < len; i++) {// 依次执行注册的消息对应的动作序列__messages[type][i].call(this, events);}
}

1.3 消息注销方法

“将订阅者注销的消息从消息队列中清除”

remove: function(type, fn) {// 如果消息队列存在if(__messages[type] instanceof Array){// 从最后一个消息动作遍历var i = __message[type].length - 1;for(; i>= 0; i--) {// 如果存在该动作则在消息动作序列中移除相应动作__messages[type][i] === fn && __messages[type].splice(i, 1);}}
}

2.面向对象对象的程序设计

  • 参考JavaScript高级程序设计(第三版)

面向对象(Object-Oriented, OO)的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。ECMAScript中没有类的概念,因此它的对象也与类的语言的对象有所不同。

ECMA-262把对象定义为:“无序属性的集合,其属性可以包含基本值、对象或者函数”。严格来讲,这就相当于说对象是一组没有特定顺序的值。对象的每个属性和方法都有一个名字,而每个名字都映射到一个值。正因为这样,我们可以把ECMAScript的对象想象成散列表:无非就是一组名值对,其中值可以是数据或函数

2.1 理解对象

  • 创建一个对象的最简单方式
  • 创建一个Object的实例,然后再为它添加属性和方法
var person = new Object();
person.name = "Nicholas";
person.age = 29;
person.job = "Software Engineer";
person.sayName = function() {alert(this.name);
};

早期的JavaScript开发人员使用上述方法创建对象。几年后,对象字面量成为创建这种对象的首选模式:

var person = {name: "Nicholas",age: 29,job: "Software Engineer",sayName: function(){alert(this.name);}
};

2.1.1 属性类型

ECMA-262第5版在定义只有内部才用的特征(attribute)时,描述了属性(property)的各种特征。ECMA-262定义这些特性是为了给JavaScript引擎用的,因此在JavaScript中我们不能直接访问它们。为了表示特性是内部值,该规范把它们放在了两对儿方括号中,例如[ [Enumerable] ]

  1. 数据属性
    数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有4个描述其行为的特性

    • [ [Configurable]]: 表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。像前面例子中那样直接在对象上定义的属性,默认为true。
    • [ [Enumberable]]:表示能否通过for-in循环返回属性,默认为true。
    • [ [Writable]]:表示能否修改属性的值,默认为true。
    • [ [Value]]:属性的数据值,默认为undefined

    对于像前面栗子中的那样直接在对象上定义属性,它们的[ [Configurable]]、[ [Enumberable]]和[ [Writable]]特性都被设置为true,而[ [Value]]特性被设置为指定的值。

var person = {name: "Nicholas"
}

要修改属性默认的特性,必须使用ECMAScript5的Object.defineProperty()方法。这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符(descriptor)对象的属性必须是:configurable、enumerable、writable和value。

var person = {};
Object.defineProperty(person,"name", {writable: false,value: "Nicholas"
});
  1. 访问器属性
    访问器属性不包含数据值;它们包含一对儿getter和setter函数。在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter函数并传入新值,这个函数负责决定如何处理数据。
  • [[Configurable]]: 表示能否通过delete删除属性从而重新定义属性。
  • [[Enumerable]]: 表示能否通过for-in循环返回属性。
  • [[Get]]:在读取属性时调用的函数,默认值为undefined
  • [[Set]]:在写入属性时调用的函数,默认值为undefined

访问器属性不能直接定义,必须使用Object.defineProperty()来定义。

var book = {_year: 2004,edition: 1
};
Object.defineProperty(book, "year", {get: function() {return this._year;},set: function(newValue) {if(newValue > 2004){this._year = newValue;this.edition += newValue - 2004;}}
});
book.year = 2005;
alert(book.edition);

2.1.2 定义多个属性

ECAMAScript5 又定义了一个Object.defineProperties()方法。利用这个方法可以通过描述符一次定义多个属性

var book = {};
Object.defineProperties(book, {_year: {writable: true,value: 2004},edition: {writable: true,value: 1},year: {get: function() {return this._year;},set: function(newValue) {if(newValue > 2004) {this._year = newValue;this.edition += newValue - 2004;}}}
});

2.1.3 读取属性的特性

使用ECMAScript5的Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述符。这个方法接收两个参数: 属性所在的对象和要读取其描述符的属性名称。返回值是一个对象,如果是访问器属性,这个对象的属性又configurable、enumerable、get和set;如果是数据属性,这个对象的属性又configurable、enumerable、writable和value。

var book = {};
Object.defineProperties(book, {_year: {value: 2004},edition: {value: 1},year: {get: function(){return this._year;},set: function(newValue){if (newValue > 2004) {this._year = newValue;this.edition += newValue - 2004;}}}
});
var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
alert(descriptor.value);    // 2004
alert(descriptor.configurable);   // false
alert(typeof descriptor.get);   // "undefined"var descriptor = Object.getOwnPropertyDescriptor(book, "year");
alert(descriptor.value);
alert(descriptor.enumerable);
alert(typeof descriptor.get);

2.2 工厂模式

  • 对象字面量的缺点: 使用同一个接口创建很多对象,会产生大量的重复代码
  • 抽象了创建具体对象的过程
  • 考虑到ECMAScript中无法创建类,开发人员发明了如下函数:
function createPerson(name, age, job) {var o = new Object();o.name = name;o.age = age;o.job = job;o.sayName = function(){alert(this.name);};return o;
}
var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");
  • 工厂模式的缺点: 没有解决对象识别问题,即怎样知道一个对象的类型.(如上面应该可以检测出是一个createPerson类)

2.3 构造函数模式

  • ECMAScript中的构造函数可用来创建特定类型的对象。
function Person(name, age, job) {this.name = name;this.age = age;this.job = job;this.sayName = function(){alert(this.name);};
}
var person1 = new Person("Nicholas", 29, "Softwate Engineer");
var person2 = new Person("Greg", 27, "Doctor");

2.3.1 构造函数和工厂模式的区别

  • 没有显示地创建对象
  • 直接将属性和方法赋给了this对象
  • 没有return语句

2.3.2 new构造函数

  • 使用new操作符调用构造函数,实际上会经历以下4个步骤:
    (1) 创建一个新对象;
    (2) 将构造函数的作用域赋给新对象(this就指向了这个新对象);
    (3) 指向构造函数中的代码(为这个新对象添加属性);
    (4) 返回新对象

[栗子]:

  1. 检测person1是不是Person的实例
console.log(person1 instanceof Person);

创建自定义的构造函数意味着将来可以将它的实例标识为一种特定的类型。

2.3.3 不使用new操作符调用构造函数

function Person(name, age, job) {this.name = name;this.age = age;this.job = job;this.sayName = function(){alert(this.name);}
}
Person("Greg", 27, "Doctor");
alert(Window.name);     // "Greg"
  • 将会在全局对象上挂载这些属性和方法.

2.3.4 构造函数的问题

  • 构造函数的主要问题是: “每个方法都要在每个实例上重新创建一遍”
// 前面的构造函数等价于
function Person(name, age, job){this.name = name;this.age = age;this.job = job;this.sayName = new Function("alert(this.name)");
}
  • 从以上角度来看,每一个Person实例都包含一个不同的Function实例
  • 更确切的讲,以构造函数创建的函数,会导致不同的作用域链和标识符解析
  • 以下代码可以证明函数的方法是不同的.
console.log(person1.sayName === person2.sayName);   //false

3.小结

3.1 工厂模式

  • 抽象了对象的创建过程
  • 缺点是: 使用工厂模式创建的对象是无法识别为某一个类的

3.2 构造函数模式

  • 解决了工厂模式类的识别问题.

  • 缺点是: 不同实例之间相同的方法是不同的.浪费了资源.

  • 解决办法: 原型模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/250390.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java_day19_MVC和配置文件

简单的MVC设计 MVC的全名是Model View Controller&#xff0c;是模型(model)&#xff0d;视图(view)&#xff0d;控制器(controller)的缩写&#xff0c;是一种软件设计典范。它是用一种业务逻辑、数据与界面显示分离的方法来组织代码&#xff0c;将众多的业务逻辑聚集到一个部件…

Problem I: 打印金字塔

#include<stdio.h> int main() {int n,i,j,k;scanf("%d",&n);for(i1;i<n;i){for(j1;j<n-i;j)printf(" ");for(k1;k<2*i-1;k)printf("*");printf("\n");}return 0; } HINT 用双重循环做&#xff0c;外循环代表行数&…

webpack --- 发布环境的配置 代码压缩 代码分类

说明 源代码本篇主要对发布环境的配置说明前面2点是对webpack的一个复习.第3点开始,逐步配置部署代码 1. Webpack发布的策略 2.1 在实际开发中,一般会有两套方案: 开发期间的项目:包含了测试文件、测试数据、开发工具、测试工具等相关配置,有利于项目的开发和测试,但是这些文…

salesforce lightning零基础学习(三) 表达式的!(绑定表达式)与 #(非绑定表达式)

在salesforce的classic中&#xff0c;我们使用{!expresion}在前台页面展示信息&#xff0c;在lightning中&#xff0c;上一篇我们也提及了&#xff0c;如果展示attribute的值&#xff0c;可以使用{!v.expresion}展示信息。 lightning在component中解析动态值的时候&#xff0c;…

sqlserver学习3---sql函数

一、SQL DML 和 DDL 可以把 SQL 分为两个部分&#xff1a;数据操作语言 (DML) 和 数据定义语言 (DDL)。 SQL (结构化查询语言)是用于执行查询的语法。但是 SQL 语言也包含用于更新、插入和删除记录的语法。 查询和更新指令构成了 SQL 的 DML 部分&#xff1a; SELECT - 从数据库…

JavaScript --- [学习笔记] 原型模式

说明 接JavaScript — > [学习笔记]观察者模式 & 理解对象 & 工厂模式 & 构造函数模式上一篇构造函数模式创建的实例,不同实例的同一个方法是不相等的,为了解决这个问题.出现了原型模式 1. 原型模式 具体做法是,不在构造函数中定义对象实例的信息,而是将这些…

网络协议各层概述

网络协议概述 OSI是一个开放性的通信系统互连参考模型&#xff0c;他是一个定义得非常好的协议规范。OSI模型有7层结构&#xff0c;每层都可以有几个子层。 OSI的7层从上到下分别是 7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层 1 物理层&#xff1b; 其中高层&…

A start job is running for Raise network interface(5min 13s )问题解决方法

命令&#xff1a;sudo vim /etc/systemd/system/network-online.target.wants/networking.service将里面的TimeoutStartSec5min 修改为TimeoutStartSec2sec 然后重启系统&#xff0c;就可以生效了&#xff0c;开机速度很快 转载于:https://www.cnblogs.com/sea-stream/p/98615…

javascript --- 实现对象的深拷贝

浅拷贝和深拷贝 浅拷贝: 只拷贝一层.当对象是复杂数据类型(Object、 Array)时,只拷贝引用深拷贝: 多层拷贝.复杂数据类型,会重新分配内存空间. 实现浅拷贝的2种方法 使用for ... in 实现 var obj {name: marron,age: 18,msg: {sex: "1" } } var o {}; for(let …

Qt与FFmpeg联合开发指南(二)——解码(2):封装和界面设计

与解码相关的主要代码在上一篇博客中已经做了介绍&#xff0c;本篇我们会先讨论一下如何控制解码速度再提供一个我个人的封装思路。最后回归到界面设计环节重点看一下如何保证播放器界面在缩放和拖动的过程中保证视频画面的宽高比例。 一、解码速度 播放器播放媒体文件的时候播…

Bzoj1051 受欢迎的牛

每一头牛的愿望就是变成一头最受欢迎的牛。现在有 N 头牛&#xff0c;给你 M 对整数 (A,B)&#xff0c;表示牛 A 认为牛 B 受欢迎。这种关系是具有传递性的&#xff0c;如果 A 认为 B 受欢迎&#xff0c;B 认为 C 受欢迎&#xff0c;那么牛 A 也认为牛 C 受欢迎。你的任务是求出…

node --- 模块加载机制

1. Node.js中模块加载机制 1.1 模块查找规则-当模块拥有路径但没有后缀时 require(./find.js); require(./find);require方法根据模块路径查找模块,如果是完整路径,直接进入模块如果模块后缀省略,先找同名JS文件再找同名JS文件夹 require(./find); // 以上会先找到命令行目录…

51Nod 蜥蜴和地下室(搜索)

哈利喜欢玩角色扮演的电脑游戏《蜥蜴和地下室》。此时&#xff0c;他正在扮演一个魔术师。在最后一关&#xff0c;他必须和一排的弓箭手战斗。他唯一能消灭他们的办法是一个火球咒语。如果哈利用他的火球咒语攻击第i个弓箭手&#xff08;他们从左到右标记&#xff09;&#xff…

多线程——实现Runnable接口实现一个多线程

实现Runnable接口实现一个多线程 Runnable接口源码&#xff1a; package java.lang; //Runnable接口源码只有一个run方法 public interface Runnable {public abstract void run(); } 实现Runnable的两个多线程类&#xff1a; public class RunnableThread1 implements Runnabl…

javascript --- 文件上传即时预览 闭包实现多图片即时预览

使用javascript原生功能实现,点击上传文件,然后再网页上显示出来 1. 初级显示 1.1 准备一个input标签和一个img标签 <input typefile id"file"> <img id"preview" src"">1.2 js代码如下 // 将上传的图片显示到页面上function sho…

第一次作业:深入Linux源码分析进程模型

一.进程的概念 第一&#xff0c;进程是一个实体。每一个进程都有它自己的地址空间&#xff0c;一般情况下&#xff0c;包括文本区域&#xff08;text region&#xff09;、数据区域&#xff08;data region&#xff09;和堆栈&#xff08;stack region&#xff09;。文本区域存…

关于模型验证那点事儿

今天应笑笑老师之问&#xff0c;做了一个模型验证的例子&#xff0c;发现之前对这个东西的理解太片面&#xff0c;重新整理了一下思路 字段验证优先级高于类验证 什么是类验证呢&#xff1f;就是两个字段组合的验证&#xff0c;比如你Admin不允许修改密码&#xff0c;你修改密码…

mongoose --- createUser

说明 源代码记录、遗忘回顾mongoDB默认不需要使用账号密码即可访问数据库.下面是给mongoDB添加超级管理员和普通用户的方法 以系统管理员的方式运行powershell连接数据库 mongo查看数据库: show dbs切换到admin数据库: use admin创建超级管理员账户: db.createUser({user: roo…

Win10安装MySQL5.7.22 解压缩版(手动配置)方法

1.下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/5.7.html#downloads 直接点击下载项 下载后&#xff1a; 2.可以把解压的内容随便放到一个目录&#xff0c;我的是如下目录&#xff08;放到C盘的话&#xff0c;可能在修改ini文件时涉及权限问题&#xff0c;之后我…

Elemant-UI日期范围的表单验证

Form 组件提供了表单验证的功能&#xff0c;只需要通过 rules 属性传入约定的验证规则&#xff0c;并将 Form-Item 的 prop 属性设置为需校验的字段名即可。但是官网的示例只有普通日期类型的验证&#xff0c;没有时间范围的验证。 一开始&#xff0c;我认为时间时间范围的是一…