说明

  • 本系列(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 构造函数模式

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

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

  • 解决办法: 原型模式

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

  1. JavaScript:学习笔记(9)——Promise对象

    JavaScript:学习笔记(9)--Promise对象 引入Promise Primose是异步编程的一种解决方案,比传统的解决方案回调函数和事件更加合理和强大.如下面为基于回调函数的Ajax操作 ...

  2. JavaScript学习笔记之原型对象

    本文是学习<JavaScript高级程序设计>第六章的笔记. JS中,便于批量创建对象的三种模式: 1.工厂模式:用一个函数封装创建对象的细节,传入必要的参数,在函数内部new一个对象并返 ...

  3. javascript学习笔记下篇--浏览器对象

    浏览器对象 一.事件 事件对象 事件的冒泡 事件的委派 事件的绑定/注册 常用事件 事件的传播 二.DOM对象 1.DOM查找 2.DOM树修改 DOM树添加 DOM删除和替换 3.DOM属性和样式修 ...

  4. javascript学习笔记之document对象、表单及表单元素、脚本化cookie

    一.document对象 每个window对象都有document属性.该属性引用表示在窗口中显示的HTML文档的document对象. 1.关键方法 close()关闭open方法打开的文档 ope ...

  5. JavaScript学习笔记——underscore操作对象的方法

    var obj = {a:'aaa',b:'bbb',c:'ccc'}; 1._.keys(obj)获取对象的所有属性名称 2._.values(obj)获取对象的所有属性值 3._.extend(d ...

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

    说明 接JavaScript - > [学习笔记]观察者模式 & 理解对象 & 工厂模式 & 构造函数模式 上一篇构造函数模式创建的实例,不同实例的同一个方法是不相等的, ...

  7. JavaScript学习笔记之对象及继承

    JavaScript学习笔记之对象及继承 对象属性 ES5中有两种属性,数据属性和访问器属性. 数据属性包括[[writable]](能否修改属性的值).[[value]]等等: 访问器属性包括[[C ...

  8. JavaScript学习笔记:对象

    JavaScript学习笔记:对象 1.声明对象 (1)字面量对象 <!DOCTYPE html> <html lang="en"> <head> ...

  9. JavaScript学习笔记03-数组-Data对象-Math对象-包装类-字符串-正则

    目录 一.数组 索引 数组的特点 1.1.数组的创建 1.1.1.使用new关键字(构造函数) 1.1.2.使用字面量形式 1.1.3.创建数组的注意事项 1.2.数组的基本使用 1.2.1.存操作( ...

最新文章

  1. 训练softmax分类器实例_CS224N NLP with Deep Learning(四):Window分类器与神经网络
  2. 《Programming in Lua 3》读书笔记(十二)
  3. soa面向服务体系结构_服务和面向微服务的体系结构简介
  4. SpringBoot实战教程(6)| 整合Druid
  5. 给angularJs grid列上添加自定义按钮
  6. java易错基础知识点
  7. 地理人必备的宝藏网站
  8. 背包问题 装箱问题 货盘装填问题 区别
  9. javascript 判断数据类型的几种方法
  10. EnableViewState详细分析
  11. 分享一款好用的英语词频统计软件
  12. GLSL内置数学函数部分解析
  13. 《德鲁克管理思想精要》读书笔记11 - 管理你的下半生
  14. List.stream()常用的操作
  15. LTE学习笔记4之物理层信道与信号
  16. 运用css3新属性transform写的盒子嵌套展开动画效果
  17. 第4关 注册配置中心实现
  18. java简单的增删改查项目 ATM机
  19. 技术分享:应用于厚型气体电子倍增器的高耐压PCB研究
  20. python整数除法保留两位小数

热门文章

  1. 阿里云物联网平台,三要素生成hmacmd5,hmacsha1和hmacsha256,password算法+hashmd5,hashsha1,hashsha256算法
  2. 开启mysql日志记录_Mysql开启日志记录
  3. jmeter跨线程组传多个值_Jmeter 跨线程组传递参数 之两种方法(转)
  4. python34.dll_python34.dll下载
  5. java中组合_java中组合模式详解和使用方法
  6. 多GPU运行Deep Learning 和 并行Deep Learning(待续)
  7. GitHub 新出的 Actions 是什么? 用他做自动测试?
  8. flutte的第一个hello world程序
  9. SVN_06导入项目文档
  10. 9. 弹出键盘挡住input