内容要点:

一.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. D3.js:动态效果

    D3 提供了 4 个方法用于实现图形的过渡: - transition() 启动过渡效果,其前后是图形变化前后的状态(形状.位置.颜色等等),例如: .attr("fill",&q ...

  2. CFRound#379(div2)

    题目链接:http://codeforces.com/contest/734 A:SB题. #include<cstdio> #include<cstring> #includ ...

  3. Java 后台sql注入

    JdbcTemplate.update(sql, ArrayList.toArray()) Connection conn = null; PreparedStatement ps = null; c ...

  4. android studio 将library导出为jar 亲测成功

    本人使用的是helloChart这个开源项目,其主要用于图表,来自git 地址为:https://github.com/lecho/hellocharts-android 下载命令为 git clon ...

  5. sphinx cmd command

    D:\iso\gaoqiao\app\sphinx\bin\indexer.exe -c D:\iso\gaoqiao\app\sphinx\bin\sphinx.conf --all --rotat ...

  6. get与post请求

    1.post请求 如果表单以Post方式提交过来的,接收时必须以Requert.Form来接收,并且表单元素必须有name属性,而Form指定的键的名称就是name属性的值 <form meth ...

  7. HDU 5887 Herbs Gathering

    背包,$map$,优化. 和普通背包一样,$map$加一个$erase$优化一下就可以跑的很快了. #pragma comment(linker, "/STACK:1024000000,10 ...

  8. ModelState.IsValid一直为false的原因

    一,问题:ModelState.IsValid一直为false 二,解决方法和原因, 由于这个方法中传过来的RegisterForm模型的字段,某一个为空值,则会造成这个验证验证为false,去注释掉 ...

  9. 【Python】使用多个迭代器

    如果要达到多个迭代器的效果,__iter__()只需替迭代器定义新的状态对象,而不是返回self class SkipIterator: def __init__(self, wrapped): se ...

  10. Oracle新实例创建

    http://blog.itpub.net/29519108/viewspace-1443918/ 刚开始创建时,千万别点容器数据库,不然后面新建用户时,用户名前得加C##. 常用命令: sqlplu ...