首页 > 程序开发 > web前端 > JavaScript >

JavaScript中的Java式继承实例讲解

2018-07-23

JavaScript中的Java式继承实例讲解。区别:Java类似的强类型面向对象语言,类为。实例字段:他们是基于实例的属性或变量,用以保存独立对象的状态

JavaScript中的Java式继承

区别

Java类似的强类型面向对象语言,类为

实例字段

他们是基于实例的属性或变量,用以保存独立对象的状态

实例方法

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

类字段

这些属性或者变量是属于类的,而不是属于类的某个实例的

类方法

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

js和Java的不同之处

js的函数是以值的形式出现的,方法和字段没有太大的区别,如果属性值是函数,那么这个属性就定义了一个方法,否则仅仅是一个普通的属性或者字段,用js模拟出Java的这四种类成员类型。js中有三种不同的对象,三种对象的属性和行为和下方的类似

构造函数对象

构造函数为js的类定义名称,任何添加到这个构造函数对象中的属性都是类字段和类方法。(如果属性值是函数的话为类方法)

原型对象

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

实例对象

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

js中定义类的方法

先定义一个构造函数并设置初始化实例对象的属性 给构造函数的prototype对象定义实例的方法 给构造函数定义类字段和类属性

实现一个表示复数的类

先讨论try和catch的错误处理机制

首先出现throw会直接暂停执行,之前已经说过了

/*这是一个使用try和catch的示范程序*/
function a() {
  try {
    throw '发生错误';
    return 'O(∩_∩)O哈哈~';
  } catch(x) {
    throw '继续发送错误';
  }
}

如果程序没有内容会直接执行try,但是由try必须有catch(仅仅是当程序内容为空的情况下),但是对于其扫尾的finally来说则是不一定的,仅此而已

叮, 又发现一个框架 https://formatjs.io/ 不急慢慢来

一些下方要用到的方法

Math.sqrt 平方根

exec()字符串匹配 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec

制定一个字符串,进行匹配操作

parseFloat() 函数解析一个字符串参数并返回一个浮点数。

下面是完整的一个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;     // 复数的虚部
};

/*
 * 类的实例方法定义为原型对象的函数值属性
 * 这里的定义的方法可以被所有实例进行继承(因为是在其属性上直接添加prototyp,而不是__proto__的,是在其子代直接进行继承的
 * js的实例的方法必须使用this,因为是方法,不是属性,也不是一些帮助运行的属性,再次重复是方法,方法是用来进行对于对象进行处理的
 * 这里是用this来存取实例的字段的
*/

// 当前复数对象加上另外一个复数,并返回一个新的计算和值后的复数对象
Complex.prototype.add = function (that) {
    return new Complex(this.r + that.r, this.i + that.r);
};

// 当前复数乘以另外一个复数,并返回一个新的计算乘积之后的复数对象
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 Math.sqrt(this.r * this.r + this.i * this.i);
};

// 复数求负运算
Complex.prototype.neg = function () {
    return new Complex(-this.r, -this.i);
};

// 将复数对象转换为一个字符串
Complex.prototype.neg = function () {
    return '(' + this.r + ',' this.i + ')';
};

// 检测当前复数对象是否和另外一个复数值相等
Complex.prototype.equals = function (that) {
    return that != null &&  // 该对象必须有定义,为了防止两个值是空值仍然相等的情况,至于为什么能分行写,是因为没有结束,并且用&&作为语句的连接,使其变为一个语句
    that.constructor == Complex &&  // 比较的另外一个复数必须是Complex的类,否则无法比较
    this.r === that.r && this.i === that.i // 实部必须和虚部相等,一般比较使用严格相等比较运算符,因为严格相等比较运算符比相等比较运算符更加严格,也跟加安全,防止出现undefined或者null的问题
};

/* 类字段(比如常量)和类方法直接定义为构造函数的属性(这里是用来书写一些构造函数的属性的)
 * 需要注意的是,类的方法通常不使用this 这是因为一般js使用类的时候是new,而new的过程是,先创建一个空对象,然后将对象的原型链进行赋值(prototype),然后再将空对象的方法,进行赋值,其中全是赋值,并没有使用其对象的方法,所以一般不使用this
 * 并且,类仅仅是作为一个工厂生产相关的函数,仅此而已。因为只作为生产,而不进行更改,同样也不使用this
 * 这些只是对其参数进行操作。参考上一条
 */

// 这里预定了一些对复数运算的有帮助的类字段
// 这里的类方法通常不使用关键字this
// 他们的命名全是大写,用来表明他们是常量,用来进行替代某些内容
// 在ES5中的这些类字段的属性值为只读
Complex.ZERO = new Complex(0, 0);   // 使用这个常量创建一个新的对象
Complex.ONE = new Complex(1, 0);
Complex.I = new Complex(0, 1);

// 这个类方法将由实例对象的toString方法返回的字符串格式解析为一个Comoplex对象的parse属性
// 即这个类方法是是将字符串进行解析的一个类方法
// 使用try的原因是因为js为单线程的,即使捕获异常,避免线程调用失败(毕竟为单线程的嘛) 部分异常不重要,放置局部影响到全局(降低耦合性) 进行对项目的分层,MVC模式,方便更加‘优雅’的找出错误(*^__^*) 嘻嘻……防止找错误的时候不必要心慌,这是关键(⊙o⊙)
// 或者抛出一个类型错误异常
// 因为这里是另外的处理,和其余不同,所以命名使用_开头,方便进行查找
Complex.parse = function(s) {
    try {   // 假设解析成功
        var m = Complex._format.exec(s);    // 利用正则表达式进行匹配
        return new Complex(parseFloat(m[1]), parseFloat(m[1]));
    } catch(x) {    // 如果解析失败则抛出异常
        throw new TypeError("can't parse '"+ s"'as a complex number.");
    }
};

// 定义类的私有字段,这个字段在Complex.parse()中用到了
// 依旧,命名,下划线前缀表明是类的内部使用的,不属于类的公有api部分,因为公有api部分要使用prototype进行继承
Complex._format = /^\{([^,]+), ([^}]+)\}&/;

// \(^o^)/完成啦~\(≧▽≦)/~啦啦啦
相关文章
最新文章
热点推荐