本章题目是继承,实质上介绍JS如何实现面向对象的三大特性,封装,继承,多态。本章的最后一个小节介绍事件。

  与Java语言对比,虽然名称同样称为类,对象,但是显然它们的含义存在一些细微的差异,而且实现三大特性的方式存在很大差异。所以用Java的概念去理解JS中的面向对象反而会很困惑。

  从实际效果看,JS同样可以实现复杂的类结构,例如easyui中存在工具类(parser,loader),接口(resizable,draggable,droppable),继承(validatebox,textbox,maskedbox),组合(datebox是由textbox,calendar)等,分析这些组件之间的关系已不那么简单。所以JS还是很强大的。

  个人感觉本章的重点是理解JS的继承概念是对象与对象之间的继承,区别Java语言中类与类之间的继承。

  原文总共包含六个小节,结构如下:

  1. 第一小节介绍继承的概念以及JS语言实现继承的概念。
  2. 第二小节介绍虚伪的继承,并演示继承的示例。
  3. 第三小节介绍将多个参数封装为对象,这里的参数更偏向于构造器的参数,这些参数将作为类的实例成员。
  4. 第四小节介绍通过原型链实现继承
  5. 第五小节介绍通过函数私有变量实现封装
  6. 第六小节介绍事件。

1、继承概念

本小节总共分为五段,

第一段为一句话,阐述继承在面向对象语言中的重要性。

第二段阐述继承的优点

  1. 代码复用,子类可以直接使用父类中继承得到的属性和方法。
  2. 继承是实现复杂类结构的重要手段,父类与之类存在泛化关系。

第三段阐述的是类转换,在Java语言或其他面向对象语言中,父类与子类之间的转换,当需要父类时,子类可以自动转换为父类;当需要子类时,父类必须强转换为子类。而在JS中不存在这种类型转换。

第四段阐述的是JS语言的面向对象特性不比其他语言差。

第五段阐述的是JS实现继承的机制,理解这段话很重要。

  在Java语言中,继承通常发生在类与类之间,而在JS语言,继承发生在对象与对象之间。类是一组公共事物的抽象,它并不存在,实际上是一个概念,例如大学,人。对象是现实事物的一个抽象,它反应实际存在的事物,例如北京大学,张三。类与对象之间的关系,是抽象到具体的关系。

  Java语言中继承发生在类与类之间,医生,律师,工人,农民,官员继承人,它的角度是工作的职责,父亲,母亲,孩子,兄弟继承人,它的角度是家庭的关系。而对象张三可以是工人,在第二种角度中,它可以是父亲,孩子,兄弟等等,角色可以是互斥的,也可以是同时存在的,但是所有的这些都是更全面认识对象张三的抽象概念,如果角度更多,认识张三也更全面,但是对象是同一个。

  在JS语言中继承是发生在对象与对象之间,假设这里类是人,对象是张三,李四,王五等等,张三继承李四,在初次接触时,疑惑很多,想不通。随着JS语言的经验增加,理解对象与对象之间概念更偏向于模板与实物之间的关系,两者都是同时存在的。举个简单的示例,月饼的模板与月饼之间的关系,可以看出月饼模板的作用就是为了产生月饼,它并没有其他的用途。对比构造器与new创建的对象之间的关系,构造器的用途就是为了产生这类对象,构造器自身确实也可以调用,也可以被当做函数独立存在,但是它是没有意义的。

父对象与子对象之间的关系,产生父对象只是为了更方便的产生子类对象,父对象是子对象的模板。

2、继承的实现

拥有相同原型链的对象为同类。可以理解为调用Object.getPrototypeOf返回相同对象的实例为同类。

在继续之前,需要理解prototype属性,原型链,以及对象自身三者的关系。

假设将原型链理解为月饼模板,而对象理解为月饼。那么创建对象的一般步骤如下。

  1. 首先创建一个月饼模板,或者利用已经存在的月饼模板。本质是创建一个原型链对象,这个对象是什么样并不知道,但是它不能是基本数据类型,例如字符串,数字,布尔等。
  2. 完善这个模板,可以理解为给原型链对象添加方法和属性。
  3. 建立月饼模板与月饼之间的关系,可以理解为原型链对象必须与新对象存在原型链关系,之前它们只是两个独立的对象而已。
// 创建模板对象
var templateObj = {};
// 这样新建立的对象会与模板对象之间产生原型链关系
var obj = Object.create(templateObj);
// 给模板对象添加方法
templateObj.hello = function(){
console.log("Hello "+ this.name);
}
// 新对象属性
obj.name = "张三";
// 调用模板中的方法
obj.hello();

  在创建对象的关键在于建立模板对象与对象的原型链关系,这种方式有两种,一种是Object.create(templateObj),另外一种方式是构造器function Templateobj();推荐使用构造器方式,上述示例只是为了演示继承关系。对于模板对象,是没有任何限制的,它可以是Function,Object,亦或者其他任何对象。

3、封装参数

  当使用构造器方式创建对象时,如果需要传入很多参数,可以将其封装为对象,具体可以参考任意UI组件的options对象,在编写时必须考虑参数是否必填,不是必填情况下必须设置合适的默认值,防止出现错误。例如在easyui的datagird组件,columns列肯定是必填的,很多其他配置项都有默认值。

4、构造器方式

  在第二小节中已经演示了如何使用原型链实现继承,在原书中第二小节演示如何使用构造器实现继承。

  构造器实现继承比较简单。

// 同时prototype属性,
// 该属性值为一个对象,它拥有constructor属性,属性值为TemplateObj, TemplateObj.prototype = {constructor:TemplateObj}
// 并将该对象作为new出来对象的原型链对象。
function TemplateObj(name) {
this.name = name;
}
// 完善模板,添加一些方法
TemplateObj.prototype.hello = function () {
console.log("Hello " + this.name);
};
// 绑定新对象与模板对象之间的原型链关系,此时Object.getPrototypeOf(obj) === TemplateObj.prototype
var obj = new TemplateObj("张三");
obj.hello();

5、封装

  封装的实现利用的是函数的私有作用域。实现封装的步骤如下

  1. 创建任意函数private,它的作用是提供私有的作用域。
  2. 在函数中定义任意的变量,这些变量为对象的私有属性。
  3. 在函数中创建对象,并将该对象返回,该对象包含所有的公共属性。
function Person(name) {
// 私有属性
var age = 21;
// 私有属性
var country = "中国";
// 公共属性
var hello = function () {
console.log("Hello " + this.name + "年龄为:" + age + "国家为:" + country);
};
// 创建新对象
var person = {
name:name,
hello: hello
};
return person;
}

6、事件

  事件的三个主要过程是注册事件,触发事件,关联的事件处理器运行。本小节中引用原书的例子,其中触发事件的操作只能是主动去调用本例中的fire方法。

// 给对象添加事件相关的方法
var eventuality = function (that) {
// 注册事件的对象,它的key为事件的类型,为字符串
// 它的value为事件处理器数组,每个数组中都包含一个handler对象,
// 每个handler都拥有两个属性,method:处理器方法;parameters:处理器方法的参数
var registry = {};
// 注册事件,第一个参数为事件类型,第二个参数为处理器方法,第三个参数为处理器的参数
// 当事件已存在时,将处理器方法和参数构成新对象handler,添加到数组当中
// 当事件不存在时,key = type; value = [handler];
that.on = function (type, method, parameters) {
var handler = {
method: method,
parameters: parameters
};
if (registry.hasOwnProperty(type)) {
registry[type].push(handler);
} else {
registry[type] = [handler];
}
return this;
};
// 触发事件,本质上是根据事件的类型找到对应的处理器数组,循环数组,运行其中的方法
that.fire = function (event) {
var array; // 临时保存事件对应的处理器数组,包含一个个handler对象
var func; // 临时保存handler对象中的处理器方法
var handler; // 临时保存处理器对象
var i; // 循环变量i
// 临时保存处理器方法的参数,当handler的参数属性为空时,将event作为参数
var type = typeof event === "string" ? event : event.type;
// 循环执行
if (registry.hasOwnProperty(type)) {
array = registry[type];
for (i = 0; i < array.length; i++) {
handler = array[i];
func = handler.method;
if (typeof func === "string") {
func = this[func];
}
func.call(this, handler.parameters || [event]);
}
}
return this;
};
return that;
};

前端——语言——Core JS——《The good part》读书笔记——第五章节(Inheritance)的更多相关文章

  1. 前端——语言——Core JS——《The good part》读书笔记——初篇

    本书是一本经典,优秀的JS书籍. 目的 在书籍中作者多次提及本书的目的,让读者去发现语言中的精华部分,避免糟粕部分,提高代码的编写质量.简述为取其精华去其糟粕. 本书的内容只涉及到Core JS部分, ...

  2. 前端——语言——Core JS——《The good part》读书笔记——第四章节(Function)

    本章介绍Function对象,它是JS语言最复杂的内容. Java语言中没有Function对象,而是普通的方法,它的概念也比较简单,包含方法的重载,重写,方法签名,形参,实参等. JS语言中的Fun ...

  3. 前端——语言——Core JS——《The good part》读书笔记——第九,十章节(Style,Good Features)

    第九章节 本章节不再介绍知识点,而是作者在提倡大家培养良好的编码习惯,使用Good parts of JS,避免Bad parts of JS.它是一篇文章. 本文的1-3段阐述应用在开发过程中总会遇 ...

  4. 前端——语言——Core JS——《The good part》读书笔记——第一章节(Good Parts)

    本章是引言,有四个小节,具体内容如下: 第一小节 第一小节介绍作者的观点,作者编写本书的目的. 原文:I discovered that I could be a better programmer ...

  5. 前端——语言——Core JS——《The good part》读书笔记——第七章节(正则)

    本章介绍正则表达式的内容.正则表达式是一门独立的语言,它拥有自己的语法规则,在学习本章之前需要了解基本的语法规则. 正则表达式是通用的,意味着同样的语法规则可以适用于不同的编程语言,相同的正则表达式在 ...

  6. 前端——语言——Core JS——《The good part》读书笔记——第三章节(Object)

    本章介绍对象. 在学习Java时,对象理解为公共事物的抽象,实例为具体的个例,对象为抽象的概念,例如人为抽象的概念,具体的个例为张三,李四. Java对象种类多,包含普通类,JavaBean,注解,枚 ...

  7. 前端——语言——Core JS——《The good part》读书笔记——第六章节(Arrays)

    本章介绍数组的内容,Java中的数组在创建时,会分配同等大小的内存空间,一旦创建数组的大小无法改变,如果数据超过数组大小,会进行扩容操作.并且数组的元素类型在创建时必须是已知的,而且只能存放相同数据类 ...

  8. 前端——语言——Core JS——《The good part》读书笔记——第八章节(Methods)

    本章介绍JS核心对象的方法.这些对象包括Array,Function,Number,Object,RegExp,String.除这些常用的核心对象还有Date,JSON. 本章更偏向于API文档,介绍 ...

  9. 前端——语言——Core JS——《The good part》读书笔记——附录三,四,五(JSLint,铁路图,JSON)

    1.JSLint 本书的JSLint部分只是一个引言,详细了解该工具的使用参考http://www.jslint.com/ 2.铁路图 在本书中使用过的铁路图集中放在这部分附录中,其实读完本书之后,没 ...

随机推荐

  1. [Agc081F/At2699] Flip and Rectangles - 单调栈,结论

    [Agc081F/At2699] 给出一个拥有 \(H\times W\) 个格子的棋盘,每个格子的颜色为黑色或白色. Snuke 可以进行任意次下列操作: 选择棋盘中的一行或一列,将这一行或一列的颜 ...

  2. bootstrap-datatimepicker插件的使用

    1.引入相关的css.js文件(因为是bootstrap的,首先应该引入bootstrap.css和bootstrap.js): <link rel="stylesheet" ...

  3. arm汇编笔记

    ARM汇编(非虫笔记) 1.ARM汇编的目的: 分析elf文件的需要. 2.原生程序生成过程. (1)预处理,编译器处理c代码中的预处理指令. gcc -E hello.c -o hello.i (2 ...

  4. C++ socket编程-转载

    转自:https://www.cnblogs.com/L-hq815/archive/2012/07/09/2583043.html 若有违规请联系我删除. 介绍 Socket编程让你沮丧吗?从man ...

  5. 右键添加IDEA打开

    在安装IntelliJ IDEA时可能没有选择文件用idea打开的选项,现在有这个需求. 下面就演示一下,如何添加文件右键用idea打开! 1. 打开注册表 win+R键输入regedit 2. 找到 ...

  6. 白面系列 mongoDB

    mongoDB和redis一样,都是noSQL技术之一. redis是Key-Value存储,mongoDB是文档存储. 文档存储一般用类似json的格式存储,存储的内容是文档型的.文档是一组键值(k ...

  7. KMP小扩展,找出子串在主串中出现的所有位置

    KMP算法能够高效地匹配字符串,找出子串(T串)在主串(S串)中出现的首个位置的原算法网上已经有很多优秀的博文进行详细讲解,这里就不多赘述. 这篇博文主要是对KMP原算法稍作改动,使其能够在主串中把所 ...

  8. python之路函数

    1.函数参数,引用 2.lambda表达式 lambda表达式 f1 = lambda a1,a2: a1+a2 3.python的内置函数 abs(),绝对值 all(),循环参数,如果每个元素都为 ...

  9. C++-POJ2960-S-Nim-[限制型Nim]

    每次只能从取集合S中个数的物品,其他和普通Nim游戏相同 预处理出每种物品堆的sg值,然后直接xor一下,xor-sum>0即必胜 #include <set> #include & ...

  10. python&selenium自动化测试实战项目

    https://www.cnblogs.com/linuxchao/p/linuxchao-python-selenium-demo.html