【09类和模块】——3:javascript中java式的类继承
2016-03-27 18:51
591 查看
上一篇博文【09类和模块】——2类和构造函数
这里我们来说一下javascript中java式的类继承,如果你有过java或其他类似的强类型的面向对象编程语言开发的经历的话,你会发现javascript和java的类的不同之处在于——javascript中的函数都是以值得形式出现的,方法和字段之间并没有太大的区别。如果属性是一个函数,那么这个属性就定义一个方法,否则,它只是一个普通的属性或者叫“字段”;
但是我们还是可以模拟出java中的类的
如果你看前面写的博文,你会知道javascript中的类牵扯三种不同的对象
1、构造函数对象(任何添加到构造函数对象中的属性都是类字段或者类方法)
2、原型对象(原型对象的属性被类的说有实例所继承)
3、实例对象(类的所有实例对象都独立的,直接给这个实例定义的属性不会被所有实例对象所共享)
javascript中定义类的步骤可以缩减为三步
1、先定义一个构造函数,并设置初始化新对象的实例属性
2、给构造函数的prototype对象定义实例实例
3、给构造函数定义类字段和类属性
接下来我们将这三个步骤封装进一个简单的defineClass()函数中
先做一个准备工作,定义一个extend函数,用于将一个对象的属性和值复制到另外一个对象中
接下俩定义一个简单的类
利用上面封装的这个函数,我们重新定义一下【09类和模块】——2类和构造函数 中的Range类
上面的是封装了一个defineClass()函数来实现类似java中的类,下面我们在定义一个更长一点的类——表示复数的类Complex.js类
类的实例方法定义为原型对象的函数值属性,这里定义的方法可以被所有的实例继承,并为他们提供共享的行为
注意:在这些方法中必须使用this关键字来存取实例属性
类字段(比如常量)和类方法直接定义为构造函数的属性
需要注意的是,类的方法通常不使用this关键字,它们只对参数进行操作
上面是定义一个类的全过程,如果还需要增加实例方法,可以在原型对象上继续添加,这里我们用到了构造函数,实例字段、实例方法、类字段、类方法,下面我们类运用一下这个类
尽管javascript可以模拟出java式的类成员,但是java中很多重要的特性是无法在javascript中模拟的
1、对于java实例方法来说,实例字段可以用做局部变量,而不需要使用this关键字来引用它们,但是javascript没办法模拟这个特性,但可以使用with语句来近似的实现
2、在java中可以使用final声明字段为常量,并且可以将字段和方法声明为private,用来表示他们是私有成员且在类的外面是不可见的,在javascript中并没有这些关键字,但是javascript中的私有属性也可以用闭包里的局部变量来模拟
期待你阅读下一篇博文【09类和模块】——4:类的扩充
这里我们来说一下javascript中java式的类继承,如果你有过java或其他类似的强类型的面向对象编程语言开发的经历的话,你会发现javascript和java的类的不同之处在于——javascript中的函数都是以值得形式出现的,方法和字段之间并没有太大的区别。如果属性是一个函数,那么这个属性就定义一个方法,否则,它只是一个普通的属性或者叫“字段”;
但是我们还是可以模拟出java中的类的
如果你看前面写的博文,你会知道javascript中的类牵扯三种不同的对象
1、构造函数对象(任何添加到构造函数对象中的属性都是类字段或者类方法)
2、原型对象(原型对象的属性被类的说有实例所继承)
3、实例对象(类的所有实例对象都独立的,直接给这个实例定义的属性不会被所有实例对象所共享)
javascript中定义类的步骤可以缩减为三步
1、先定义一个构造函数,并设置初始化新对象的实例属性
2、给构造函数的prototype对象定义实例实例
3、给构造函数定义类字段和类属性
接下来我们将这三个步骤封装进一个简单的defineClass()函数中
先做一个准备工作,定义一个extend函数,用于将一个对象的属性和值复制到另外一个对象中
function extend(o,p){ for(var prop in p){//遍历p中的所有属性 o[prop]=p[prop];//将属性和值复制到o中 } return o; }
接下俩定义一个简单的类
function defineClass(constructor,methods,statics){ if(methods) extend(constructor.prototype,methods); if(statics) extend(constructor,statics); return constructor } /* constructor——用以设置实例的属性的函数 methods——实例的方法,赋值到原型中 statics——类属性,复制至构造函数中 */
利用上面封装的这个函数,我们重新定义一下【09类和模块】——2类和构造函数 中的Range类
var SimpleRange=defindeClass( function(f,t){this.f=f;this.t=t}, { includes:function(x){return this.from <=x && x<=this.to;}, foreach:function(f){ for(var x=Math.ceil(this.from);x<this.to;x++) f(x) } }, {upto:function(t){return new SimpleRange(o,t)}} )
上面的是封装了一个defineClass()函数来实现类似java中的类,下面我们在定义一个更长一点的类——表示复数的类Complex.js类
/* Complex.js这个文件定义了Complex类,用来描述复数 复数是实数和虚数的和,并且叙述i是-1的平方根 */ function Complex(real, imaginary) { if (isNaN(real) || isNaN(imaginary)) //确保两个参数都是数字 throw new TypeError(); this.r = real; //复数的实部 this.i = imaginary; //复数的虚部 }
类的实例方法定义为原型对象的函数值属性,这里定义的方法可以被所有的实例继承,并为他们提供共享的行为
注意:在这些方法中必须使用this关键字来存取实例属性
//下面的方法中that参数也必须是一个该累的实例化对象 //当前复数对象加上另外一个复数,并返回一个新的计算值的复数对象 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 Math.sqrt(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 && //that必须有定义且不能为null that.constructor === Complex && //that必须是Complex的实例 this.r === that.r && this.i === that.i;//必须包含相同的值 };
类字段(比如常量)和类方法直接定义为构造函数的属性
需要注意的是,类的方法通常不使用this关键字,它们只对参数进行操作
/* 这里定义一些对复数运算有帮助的类字段,它们的命名全都是大写,用于表名它们是常量 */ 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 = /^\{([^,]+),([^}]+)\}$/;
上面是定义一个类的全过程,如果还需要增加实例方法,可以在原型对象上继续添加,这里我们用到了构造函数,实例字段、实例方法、类字段、类方法,下面我们类运用一下这个类
var c = new Complex(2,3) //使用构造函数实例化对象 var d = new Complex(c.i,c.r)//同样是实例化对象,只不过用到了对象c的属性 c.add(d).toString() //=>"{5,5}":使用了实例的toString()方法 //下面这个稍微复杂一点,使用到了类方法和类字段 Complex.parse(c.toString()).//将实例对象c转换为字符串 add(c.neg()).//加上这个对象本身的负数 equals(Complex.ZERO)//结果永远是“零”,所以永远返回true
尽管javascript可以模拟出java式的类成员,但是java中很多重要的特性是无法在javascript中模拟的
1、对于java实例方法来说,实例字段可以用做局部变量,而不需要使用this关键字来引用它们,但是javascript没办法模拟这个特性,但可以使用with语句来近似的实现
Complex.prototype.toString=function(){ with(this){ return "{"+r+","+i+"}" } }
2、在java中可以使用final声明字段为常量,并且可以将字段和方法声明为private,用来表示他们是私有成员且在类的外面是不可见的,在javascript中并没有这些关键字,但是javascript中的私有属性也可以用闭包里的局部变量来模拟
期待你阅读下一篇博文【09类和模块】——4:类的扩充
相关文章推荐
- JavaScript-导航栏点击变色处理
- JSTL fn函数中字符串拼接
- js闭包
- js中typeof与instanceof用法
- Java执行JavaScript代码
- JSP中EL表达式的比较符号、字符串比较
- js 局部变量和全局变量
- Gson、Jackson和FastJSON
- 2015年最棒的10个 JavaScript 框架
- 你不知道的JavaScript--Item36 客户端检测技术
- ndk jstring 与cha*相互转换
- Javascript中匿名函数的多种调用方式
- JavaScript html5 canvas绘制时钟效果(二)
- javascript-js中技巧集合
- 修改Myecclipse servlet/jsp的默认模板
- js史上最简单的数组合并去重排序
- javascript中希望定义一个页面刷新也不能改变其值的方法
- 分享一个 原生javaScript - 用面向对象写的下拉菜单 - DropdownMenu
- js实现复制到粘贴板 ZeroClipboard
- 使用Google的Gson实现对象和json字符串之间的转换