内容要点:

一.JS中的类

1.JAVA或其他类似强类型 面向对象语言的 类成员的模样

实例字段:它们是基于实例的属性或变量,用以保存独立对象的状态。

实例方法: 它们是类的所有实例所共享的方法,由每个独立的实例调用

类字段:这些属性或变量是属于类的,而不是属于类的某个实例的。

类方法:这些方法是属于类的,而不是属于类的某个实例的

2.JS中的类牵扯三种不同的对象,三种对象的属性的行为和下面三种类成员非常相似:

构造函数对象:

之前提到,构造函数(对象)为JS的类定义了名字。任何添加到这个构造函数对象中的属性都是类字符和类方法(如果属性值是函数的话就是类方法)。

原型对象:

原型对象的属性被类的所有实例所继承,如果原型对象的属性值是函数的话,这个函数就作为 类的实例的方法 来调用

实例对象:

类的每个实例都是一个独立的对象,直接给这个实例定义的属性是不会为所有实例对象所共享的。定义在实例上的非函数属性,实际上是实例的字段。

3.JS中定义类的步骤可以缩减为一个分三步算法。

第一步,先定义一个构造函数,并设置初始化新对象的实例属性。

第二步,给构造函数的prototype对象定义实例的方法。

第三步,给构造函数定义类字段和类属性。

我们可以将这三个步骤封装进一个简单的defineClass()函数中(这里用到了例6-2中的extend()函数和例8-3中的改进版)

//一个用以定义简单类的函数

function defineClass(constructor,  //用以设置实例的属性的函数

methods, //实例的方法,复制至原型中

static)   //类属性,复制至构造函数中

{

if (methods) extend( constructor,prototype,methods );

if (statics) extend( constructor,statics );

return constructor;

}

//这是Range类的另一个实现

var SimpleRange = defineClass(function(f,t){ this.f=f;this.t=t; },

{

includes:function(x){ return this.f <=x && x<=this.t;}

toString:function(){ return this.f + "..." +this.t; }

},

{

upto:function(t){ return new SimpleRange(o,t); }});

二.例9-3 Complex.js : 表示复数的类

/*Complex.js : 这个文件定义了Complex类,用来描述复数。回忆一下,复数是实数和虚数的和,并且虚数i是-1的平方根*/

/*这个构造函数为它所创建的每个实例定义了实例字段r和i,这两个字段分别保存复数的实部和虚部,它们是对象的状态*/

function Complex(real,imaginary){

if(isNaN(real) || isNaN(imaginary)) throw new TypeError();   //确保两个实参都是数字,如果不都是数字则抛出错误

this.r = real; //复数的实部

this.i = imaginary; //复数的虚部

}

/*类的实例方法 定义为原型对象的函数值属性,这里定义的方法可以被所有实例继承,并为它们提供共享的行为。需要注意的是,JS类额实例方法必须使用关键字this来存取实例的字段。*/

//当前复数对象加上另一个对象,并返回一个新的计算和值后的复数对象

Complex.prototype.add = function(that){ return new Complex(this.r + that.r , this.i + that.i); };

//当前复数乘以另一个复数,并返回一个新的计算乘积之后的复数对象

Complex.prototype.mul = function(that){ return new Complex(this.r * that.r - this.i*that.i , this.r*that.i + this.i*that.r); };

//计算复数的模,复数的模定义为原点(0 , 0)到复平面的距离

Complex.prototype.mag = function(){ return new Complex(this.r * this.r + this.i * this.i); };

//复数的求负运算

Complex.prototype.neg = function(){ return new Complex(-this.r , -this.i); };

//将复数对象转换为一个字符串

Complex.prototype.toString = function(){ return "{" +this.r + "," +this.i + "}"; };

//检测当前复数对象是否和另外一个复数值相等

Complex.prototype.equals = function(that){ return that !=null &&          //必须有定义且不能是null

that.constructor === Complex &&     //并且必须是Complex的实例,

this.r === that.r && this.i === that.i; //并且必须包含相同的值

};

/*类字段(比如常量)和类方法 直接定义为构造函数的属性。需要注意的是,类的方法通常不使用关键字this,它们只对其参数进行操作*/

//这里预定义了一些对复数运算有帮助的类字段,它们的命名全都是大写,用以表明它们是常量(在ES5中,还能设置这些类字段的属性为只读)

Complex.ZERO = new Complex(0,0);

Complex.ONE = new Complex(1,0);

Complex.I = new Complex(0,1);

//这个类方法将由实例对象的toString方法返回的字符串格式解析为一个Complex对象,或者抛出一个类型错误异常

Complex.parse = function(s){

try{     //假设解析成功

var m = Complex._format.exec(s); //利用正则表达式进行匹配

return new Complex(parseFloat(m[1]),parseFloat(m[2]));

}catch(x){      //如果解析失败则抛出异常

throw new TypeError("Can't parse ' " + s + " ' as a complex number.");

}

};

//定义类的"私有字段",这个字段在Complex.parse()中用到了下划线前缀表明它是类内部使用的,而不属于类的公有API的部分

Complex._format = /^\{(^,]+),([^}]+)\}$/;

代码分析:

从例9-3中所定义的Complex类可以看出,我们用到了构造函数、实例字段、实例方法、类字段和类方法,看一下这段实例代码:

var c = new Complex(2,3); //使用构造函数创建新的对象

var d = new Complex(c.i , c.r); //用到了c的实例属性

c.add(d).toString(); //=>"{5,5}":使用了实例的方法

//这个稍微复杂的表达式用到了类方法和类字段

Complex.parse(c.toString()).         //将c转换为字符串

add(c.neg()).          //加上它的负数

equals(Complex.ZERO)  //结果应当永远是“零”

《JS权威指南学习总结--9.3 JS中JAVA式的类继承》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. [CSS3备忘] transform animation 等

    一些CSS不经常用就会忘记,好吧,现在整理再学习一下,也留做备忘,方便以后查看... perspective的理解: 1.数值越小,用户与3D空间Z平面距离越近,视觉效果更令人印象深刻(比如看电影,越 ...

  2. trove taskmanger api

    trove-taskmanager服务在配置实例,管理实例的生命周期以及对数据库实例执行操作方面做了很多工作.taskmanager会通过Nova.Swift的API访问Openstack基础的服务, ...

  3. java集合图示

  4. Python 自动给数字前面补0

    为了排版方便或者是输出文件命名整洁,通常需要给数字前面补0来做统一.Python中有一个zfill函数用来给字符串前面补0,非常有用,这个zfill看起来也就是zero fill的缩写吧,看一下如何使 ...

  5. cdh 安装记录

    安装文件准备 CDH 下载地址:http://archive.cloudera.com/cdh5/parcels/latest/ 下载操作系统对应的版本: 1.CDH-5.3.0-1.cdh5.3.0 ...

  6. 自己封装的tc

    封装弹窗 html <head> <script src="jquery.js"></script> <script src=" ...

  7. Attempt to write to field 'android.support.v4.app.FragmentManagerImpl android.support.v4.app.Fragment.mFragmentManager' on a null object reference

    E/AndroidRuntime﹕ FATAL EXCEPTION: mainProcess: org.example.magnusluca.drawertestapp, PID: 3624java. ...

  8. Linux下服务器环境的搭建和配置之一——Apache篇

    最近一个多月(2016-06-20开始至今),一直在忙海外广告平台FAQ系统的开发,既要负责服务器环境的搭建,又要写前端,还要写后台和数据库,甚至还要考虑产品需求和设计.所以是一个很大的挑战,对自身也 ...

  9. C#中的引用传递、值传递

      先来说下C#中的数据类型.分值类型和引用类型两大类. 值类型:直接存储数据的值,保存在内存中 引用类型:存储对值的引用,实际上存储的就是一个内存的地址 C#预定义的简单类型,像int,float, ...

  10. transient关键字小结

    java中实现序列化有两种实现方式,一种是自动的,只要实现Serilizable接口,另一种是需要手动指定需要序列化的成员变量,实现Externalizable接口. transient的特点: 1. ...