欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaScript中的Java式继承实例讲解

程序员文章站 2022-05-17 23:49:31
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^)/完成啦~\(≧▽≦)/~啦啦啦