您的位置:首页 > Web前端 > JavaScript

javascript面向对象实现java常用的1StringBuffer,Map,Collection,List,Set

2015-10-24 17:44 986 查看

javascript面向对象实现java常用的StringBuffer,Map,Collection,List,Set

1前言

       在开发中,我们做java后台开发的,普遍都是擅长后端语言,对于javascript却不甚理想。偶尔我们会去w3c看看javascript的基本语法,但是每次都是学习不到位,用起来感觉总是马马马虎虎。在最近的开发中,这个老大难的问题又出现在了我面前。一开始,继续忽略,一张手就是定义了一个function xxx(){}。但是噩梦往往都是因为懒惰造成的,由于开发的需要,某个页面的js文件多大1000 line+,方法至少也是10+了。作为一个开发人员,目睹着自己的代码,尽然会超出自己的控制,显然让人不甘心啊,于是乎,重构了很多代码,但是依旧木有使用到面向对象的编程范式。在折腾了几天后,终于下定决心,使用面向对象的技术来重写整个js文件的代码。
要想用好面向对象,那么就需要理解面向对象的编程思想,作为一个后台开发人员,就不多说了,面向对象最主要的四个特性:继承,多态,封装,抽象。更加详细的内容,请参考面向对象的相关数据。
在java中,我们使用class来定义一个类,用于规范某种对象的特性(属性,方法),当该class定义好之后,就可以使用new ClassXxx()的方式来实例化一个对象,并且所有同一个class生成的对象都具备着一致的特性(属性,方法),后期不能动态的给对象添加属性与方法。对于这种后期模式的开发语言来说,优势非常明显,那就是所有对象的属性与方法都确定了下来,并且可以通过预编译,将class转换成二进制的机器码,所以在运行效率上会比较有优势。但是缺点也同样非常明显,比如需要编译源码,不能动态添加属性或者方法,开发效率较低等。

2面向对象技术

  在javascript中,有如下几种数据类型,分别是:undefined,boolean,string,number,object,function。这里面,我们只关注object(对象)。对象是javascript的基本数据类型,将很多值聚合在一起,可以通过名字访问这些值。比如:{name:骆宏, age:20}。每一个对象除了保持自有的属性,通常还可以从一个称为原型的对象那里继承属性,通常情况下,会继承原型的方法。Javascript对象是动态的,可以动态的添加属性,或者删除属性,与java这类语言类型不一样。

2.1javascript的继承

    在java中,所有的对象都继承java.lang.Object,并且是单根继承。在javascript中也类型,所有的对象原型都继承Object.prototype对象。在这里面,我们需要特别注意的是:每个对象都引用着一个原型对象,比如Student对象引用着一个Student.prototype,并且这个Student.prototype同时也引用着Object.prototype,我们称之为javascript的原型链。下面我们假设有如下的继承关系:



  在这里面,正方形对象继承了矩形,矩形继承了多边形,多边形继承了形状,而形状继承了Object。于是正方形对象就可以获得从Object.prototype+形状.prototype+多边形.prototype+矩形.prototype的所有属性(除了一些不可以继承的属性)。一个对象在寻找属性时,会首先查找自身是否有这个属性,如果找不到,就会去到该对象的原型中选中,如果也找不到,就会递归的往Object.prototype方向去寻找该属性。我们称之为该对象的继承关系的原型链(非严肃的说法,官方定义请查阅w3c的javascript规范)。

2.2javascript对象的实例化

1工厂方式
function createCar() {
var oTempCar = new Object;  //实例化一个对象
oTempCar.color = "blue";  //给对象赋值
oTempCar.doors = 4;
oTempCar.mpg = 25;
oTempCar.showColor = function() {  //属性的值可以为方法
alert(this.color);
};
return oTempCar;  //返回对象
}
使用方式:var car = createCar();


2构造函数方式
function Car(sColor,iDoors,iMpg) {
this.color = sColor;  //使用this来表示当前的对象
this.doors = iDoors;
this.mpg = iMpg;
this.showColor = function() {  //每次创建对象时,都需要创建一个匿名函数
alert(this.color);
};
}
使用方式:var car = new Car(“红色”, “是”, “是”);

3原型方式

  在方式中2,每次创建一个Car时,都是实例化this.showColor,但是通过观察,我们可以发现,这其实是一个方法,只需要实例化一次即可。为了改进上述代码,使用原型的方式重写上诉的代码,如下:

function Car(sColor,iDoors,iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike","John");
}

Car.prototype.showColor = function() {  //将该方法放在原型的属性上,所有的Car
//对象都从这个原型对象继承该属性
alert(this.color);
};

4动态原型方式

function Car(sColor,iDoors,iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike","John");

if (typeof Car._initialized == "undefined") {  //给构造方法添加一个属性,记录下第
//一次实例化
Car.prototype.showColor = function() {
alert(this.color);
};

Car._initialized = true;   //标志着该对象已经实例化过了
}
}


5混合工厂模式

function Car() {
var oTempCar = new Object;
oTempCar.color = "blue";
oTempCar.doors = 4;
oTempCar.mpg = 25;
oTempCar.showColor = function() {
alert(this.color);
};

return oTempCar;
 

  在实际开发中,那么我们该使用哪种方式呢?在目前,原型方式与动态原型方式都比较流行,个人推荐动态原型的方式,因为可以将所有代码集中在构造函数内部,避免代码分散在多个地方。

2.3使用javascript技术模拟java中常用的类

StringBuffer

function StringBuffer(){
this.strs = [];  //用数组来缓存所有的内容

if(typeof StringBuffer._initialized == "undefined"){
StringBuffer._initalized = true;  //已经初始化过了,不需要重复初始化

StringBuffer.prototype.append = function(str){
this.strs.push(str);
return this;
};
//覆写toString,避免使用Object.toString
StringBuffer.prototype.toString = function(seperator){
if(!seperator){
seperator = "";
}
return this.strs.join(seperator);
};
}
}


Map

function Map(){
this.elements = new Array();

if(typeof Map._initialized == "undefined"){
Map._initialized = true;  //记录下已经实例化的标识符

Map.prototype.size = function(){
return this.elements.length;
};

Map.prototype.isEmpty = function(){
return this.elements.length == 0;
};

Map.prototype.clear = function(){
this.elements = new Array();
};

Map.prototype.put = function(key, value){
if(key == null || value == null) throw TypeError();

var exists = false;

if(this.isEmpty()){
this.elements.push({"key": key, "value": value});
}else{
for(var i=0; i<this.elements.length; i++){
if(this.elements[i].key == key){  //override
this.elements[i].value = value;
exists = true;
}
}

if(!exists){
this.elements.push({"key": key, "value": value});
}
}
};

Map.prototype.get = function(key){
if(key == null) throw TypeError();

if(this.isEmpty()) return null;
for(var i=0; i<this.elements.length; i++){
if(this.elements[i].key == key) return this.elements[i].value;
}
return null;
};

Map.prototype.remove = function(key){
if(key == null) throw TypeError();

if(this.isEmpty()) return false;

for(var i = 0; i < this.elements.length; i++) {
if(this.elements[i].key == key) {
this.elements.splice(i, 1);     //delete elements[i]
return true;
}
}
return false;
};

Map.prototype.containsKey = function(key){
if(key == null) throw TypeError();

if(this.isEmpty()) return false;

for(var i = 0; i < this.elements.length; i++) {
if(this.elements[i].key == key) {
return true;
}
}

return false;
};

Map.prototype.containsValue = function(value){
if(value == null) throw TypeError();

if(this.isEmpty()) return false;

for(var i = 0; i < this.elements.length; i++) {
if(this.elements[i].value == value) {
return true;
}
}

return false;
};

Map.prototype.keys = function(){
if(this.isEmpty()) return [];

var keys = new Array();
for(var i=0; i<this.elements.length; i++){
keys.push(this.elements[i].key);
}

return keys;
};

Map.prototype.values = function(){
if(this.isEmpty()) return [];

var values = new Array();
for(var i=0; i<this.elements.length; i++){
values.push(this.elements[i].value);
}

return values;
};

Map.prototype.toString = function(){
if(this.isEmpty()) return "[{}]";

var sb = new StringBuffer();
sb.append("[");
for(var i=0; i<this.elements.length; i++){
sb.append("{").append(this.elements[i].key).append(",").append(this.elements[i].value).append("}");
if(i != this.elements.length - 1){
sb.append(",");
}
}
sb.append("]");

return sb.toString();
};
}
}

Collection

function Collection(){
this.elements = new Array();
}

Collection.prototype.add = function(obj){
if(obj == null) throw TypeError();
this.elements.push(obj);
return true;
};

Collection.prototype.addAll = function(objs){
if(objs == null) throw TypeError();
this.elements = this.elements.concat(objs);
return true;
};

Collection.prototype.get = function(index){
this._checkIndex(index);

if(this.isEmpty()) return null;

return this.elements[index];
};

/**
* 删除下表为index的元素
* */
Collection.prototype.removeIndex = function(index){
this._checkIndex(index);
this.elements.splice(index, 1);     //delete elements[i-1]
};

/**
* 删除某个元素
* 这里面会从下表0开始便利,删除第一个匹配的元素
* */
Collection.prototype.removeObj = function(obj){
if(this.isEmpty()) return false;

for(var i=0; i<this.elements.length; i++){
if(this.elements[i] == obj){
this.elements.splice(i-1, 1);     //delete elements[i]
}
}
};

Collection.prototype.contains = function(obj){
if(obj == null) throw TypeError();

if(this.isEmpty()) return false;

for(var i=0; i<this.elements.length; i++){
if(this.elements[i] == obj){
return true;
}
}

return false;
};

Collection.prototype.containsAll = function(objs){
if(objs == null) throw TypeError();
if(objs.length > this.elements.length) return false;

for(var i=0; i<objs.length; i++){
if(this.contains(objs[i]) == false){
return false;
}
}

return true;
};

Collection.prototype.size = function(){
return this.elements.length;
};

Collection.prototype.isEmpty = function(){
return this.elements.length == 0;
};

Collection.prototype.clear = function(){
this.elements = new Array();
};

Collection.prototype._checkIndex = function(index){
if(index < 0 || index >= this.elements.length){
throw new Error("index must be in [0, " + this.elements.length + ")");
}
};

/**
* 默认输入的格式如下:
* [element1,element2,element3,...,elementx]
*
* 如果客户端需要获取类型数组join的效果,直接传入分隔符即可
* 比如collection的内容为:a,b,c,默认的toString为[a,b,c],如果想要获得:abc,传入"";想要获得a,b,c,传入",",想要获得a b c,传入" "
*
* */
Collection.prototype.toString = function(separator){
if(this.isEmpty()) return "";

if(separator != null){
return this.elements.join(separator);
}else{
var sb = new StringBuffer();
sb.append("[");
for(var i=0; i<this.elements.length; i++){
sb.append(this.elements[i]);
if(i != this.elements.length - 1){
sb.append(",");
}
}
sb.append("]");
return sb.toString();
}
};

List

/**
* Collection的子类
* 提供了如下几个增强方法:
* set(index, obj)
* subList
* */
function List(){
this.elements = new Array();  //这个属性不能使用Collection中的elements,因为原型对象都是collection,那样子会出现bug
}

//List.prototype修改为new Collection对象,等价于继承了Collection的所有//属性
List.prototype = new Collection();

/**
* 在第几个位置插入元素
* */
List.prototype.set = function(index, obj){
this._checkIndex(index);
this.elements.splice(index, 0, obj);     //add elements[i]
return true;
};

/**
* 获取子链表
* */
List.prototype.subList = function(start, end){
this._checkIndex(start);
this._checkIndex(end);
if(start >= end){
throw new Error("start must be less than end.");
}

var subList = new Array();
var index = 0;
for(var i=start; i<end; i++){
subList[index++] = this.elements[start];
}

return subList;
};

Set

/**
* Collection子类
* 因为Set中,元素不能重复,所以这里面override了Collection的add,addAll方法
* */
function Set(){
this.elements = new Array();  //这个属性不能使用Collection中的elements,因为原型对象都是collection,那样子会出现bug
}
Set.prototype = new Collection();  //继承Collection

/**
* 因为Set不允许重复元素存在,所以这里面需要override add,addAll方法
* */
Set.prototype.add = function(obj){
if(this.contains(obj)){
return false;
}else{
this.elements.push(obj);
return true;
}
};

Set.prototype.addAll = function(objs){
if(objs == null) throw new TypeError("objs can't be null");

for(var i=0; i<objs.length; i++){
if(this.contains(objs[i])){
continue;
}else{
this.elements.push(objs[i]);
}
}
};

/**
* 在第几个位置插入元素
* */
Set.prototype.set = function(index, obj){
this._checkIndex(index);
if(this.contains(obj)){
return false;
}else{
this.elements.splice(index, 0, obj);     //add elements[i]
return true;
}
};


3总结

     每一个后端开发人员,都应该详细的解读下javascript,而不是大概知道怎样。在实战中,可以提高开发人员的开发效率,代码的可维护性也变得不再那么狼狈不堪。下次再写javascript代码时,当你一顺手写下function xxx(){}时,请再思考下吧。

关于面向对象技术,大家可以参考: 

1 Jquery源码分析

http://www.cnblogs.com/aaronjs/p/3279314.html

 

2 w3c面向对象技术

http://www.w3school.com.cn/js/pro_js_object_oriented.asp

 

3.IBM关于javascript面向对象的讲解

http://www.ibm.com/developerworks/cn/web/1304_zengyz_jsoo/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: