javascript中的面向对象编程(一)-乾蓝洛-博客园

xiaoxiao2021-03-01  13

javascript中的面向对象编程(一)-乾蓝洛-博客园 2011年10月26日   Javaspript封装 1、面向对象语言的要求   (1)封装―把相关的信息(无论数据或方法)存储在对象中的能力   (2)聚集―把一个对象存储在另一个对象内的能力   (3) 继承―由另一个类(或多个类)得来类的属性和方法的能力   (4)多态―编写能以多种方法运行的函数或方法的能力   ECMAScript支持这些要求,因此可被看作面向对象的.   2、对象的实例化   var obj = new Object()   var ostringobj = new String()   ECMAScript中也可以把()去掉   var obj = new object;   var ostringobj = new String;   3、对象废除   ECMAScript中有无用存储单元收集程序,意味着不必专门销毁对象来释放内存.   也可强制废除对象:eg:   var obj = new Object();   obj = null   5、对象类型   5.1 本地对象   Object Array Function String Boolean Number Date RegExp Error EvalError RangeError ReferenceError SyntaxError TypeError URIError   5.2 自定义对象   6、作用域,全部都是公共的   对ECMAScript来说,讨论作用域几乎毫无意义。ECMAScript只存在一种作用域(公有作用域)   许多开发都制定了一个规约:私有的属性建议前后加下划线,如:obj._color_ = “red”;   7、静态作用域并非静态的   严格来说,ECMAScript并没有静态作用域,不过,它可以给构造函数提供属性和方法. 构造函数是函数,函数是对象,对象可以有属性和方法。   如:function sayHi(){   alert(“hi”); };   sayHi.alternate = function(){ alert(“hellow”);}   调用:   sayHi(); sayHi.alternate();   8、关键字this   在ECMAScript中,要掌握的最重要的概念之一是关键字this的用法.   它用在对象的方法中,关键字this总是指向调用该方法的对象:   eg:   var oCar = new Object();   oCar.color=“red”;   oCar.showColor=function(){   alert(this.color); //等价于 oCar.color   }   说明:利有this,可在任意多个地方重用同一个函数.   谁调用它这个this就指向谁   如:function ShowColor()   {   alert(this.Color);   }   var oCar1 = new Object();   oCar1.Color = “red”;   oCar1.ShowColor = ShowColor; //这时this是ocar1   var oCar2 = new Object();   oCar2.Color = “blue”;   oCar2.ShowColor=ShowColor; //这时this是ocar2   oCar1.ShowColor(); // output “red”   oCar2.ShowColor(); //outpub “blue”   注意:引用对象的属性时必须使用this.   eg: function ShowColor() { alert(Color); //error } 自定义类和对象   1、工厂模式   ECMAScript中对象的属性可在对象创建后动态定义.   如:   var oCar = new Object();   oCar.Color = "red";   oCar.doors = 4;   oCar.mpg = 23;   oCar.ShowColor = function(){   alert(this.Color);   }   调用时 oCar.ShowColor(); //output “red”   问题:需要创建多个Car实例怎么办?   工厂模式:   function CreateCar(){ //每次调用都创建新的实例   var oCar = new Object();   oCar.Color = "red";   oCar.doors = 4;   oCar.ShowColor = function(){   alert(this.Color);   }   return oCar;   }   调用:   var car1 = CreateCar();   var car2 = CreateCar();   car2.color=’blue’;   alert(car1.Color); //output “red”   car2.ShowColor(); //output “blue”   改造并加入参数:   function CreateCar(color,doors,mpg){   var oCar = new Object();   oCar.Color = color;   oCar.doors = doors;   oCar.mpg = mpg;   oCar.ShowColor = function(){   alert(this.Color); }   return oCar; }   var car1 = CreateCar("red",4,23);   var car2 = CreateCar("blue",4,20);   alert(car1.Color); //output “red”   car2.ShowColor(); //output “blue”   JavaScript中的封装   问题:上面的例子中,每次调用函数createCar(),都要创建新函数showColor(),意味着每个对象都有自己的showColor()版本,事实上,每个对象都共享了同一个函数,showColor每次创建都要分配内存空间   解决方法:   function showColor()   {   alert(this.color);   }   function createCar(sColor,iDoors,iMpg)   {   var oTempCar = new Object();   oTempCar.color = sColor;   oTempCar.doors = iDoors;   oTempCar.mpg= iMpg;   oTempCar.showColor = showColor;   return oTempCar;   }   var oCar1 = createCar("red",4,23);   var oCar2 = createCar("blue",3,25); oCar1.showColor(); //output “red” oCar2.showColor(); //output “blue” 问题2 问题:从功能上讲,这样解决了重复创建函数对象的问题,但该函数看起来不像对象的方法.   解决办法:   所有这些问题引发了开发者定义的构造函数的出现   构造函数方式   形式如下:   function Car(sColor,iDoors) {   this.color = sColor;   this.doors = iDoors;   this.showColor=function(){   alert(this.color); } }   // oCar.ShowColor = function(){   // alert(this.Color); }   //调用   var oCar1 = new Car(“red”,4);   var oCar2 = new Car(“blue”,4);   oCar1.showColor();   oCar2.showColor();   问题:存在着和工厂模式相同的问题,创建对象的方法,都分配内存空间   解决方法:也可以用外部函数重写构造函数,同样的,语义上无任何意义.这就是原型方式的优势所在.   function Car(){};//相当于定义了一个空的类   Car.prototype.color = “red”;//object的一个属性prototype   Car.prototype.doors = 4;   Car.prototype.showColor = function(){   alert(this.color);   }   //调用   var oCar1= new Car();   var oCar2 = new Car();   oCar1.showColor(); //output “red”   oCar2.color=“blue”;   oCar2.showColor(); //output “blue”,需要实例化的时候才分配内存空间   此种方式,调用new Car()时,原型的所有属性都被立即赋予要创建的对象,意味着所有Car实例存放的都是指向showColor()函数的指针.所有属性看起来都属于同一个对象,因此解决了前面两种方式的两个问题   可以用instanceof运算符测试对象的类型   eg: alert(oCar1 instanceof Car) //output “true”;   问题:   1、构造函数没有参数.必须创建后才能改变属性的默认值,有些讨厌   2、真正的问题在于,当属性指向对象时,对象会被多个实例共享。不灵活   如:   function Car(){};   Car.prototype.color = “red”;   Car.prototype.doors = 4;   Car.prototype.showColor = function(){   alert(this.color);   }   Car.prototype.drivers = new Array(“a”,”b”);   //call   var oCar1 = new Car();   var oCar2 = new Car();   oCar1.drivers.push(“c”);   alert(oCar1.drivers); //output “a”,”b”,”c”;   alert(oCar2.drivers); //outpub “a”,”b”,”c”;   解决方法: 联合使用构造函数和原型方式   联合使用构造函数和原型方式,就可像用其他程序设计语言一样创建对象.这种概念非常简单,即用构造函数定义对象的所有非函数属性,用原型方式定义对象的函数属性(方法).结果所有函数都只创建一次,而每个对象都具有自己的对象属性实例.   eg: function Car(sColor,iDoors){//实例化的时候不实例化ShowColor这个函数   this.color = sColor;   this.doors = iDoors;   this.drivers = new Array();   }   Car.prototype.ShowColor = function(){   alert(this.color);   }   //Call   var oCar1 = new Car(“red”,4,23);   var oCar2 = new Car(“blue”,3,25);   oCar1.drivers.push(“a”);   oCar2.drivers.push(“b”);   alert(oCar1.drivers); //output “a”;   alert(oCar2.drivers); //output “b”;   } 问题:此种方式已接近完善   但类的定义分散在两部分,感觉还不是很完美   解决办法:   动态原型方法   Function Car(sColor,iDoors,iMpg){   this.color = sColor;   this.doors = iDoors;   this.mpg = iMpg;   this.drivers=new Array();   if (typeof Car._initialized==“undefined”){//initialized随便起的,刚创建的时候肯定不存在   Car.prototype.showColor = function(){   alert(this.color);   };   Car._initialized = true;   //下次再定义这个类的实例,initalized就有值了,就不会重新定义这个方法了   }   }   //call   } var oCar = new Car("yellow",10,20);   } oCar.showColor(); //output “yellow”   采用哪种方式?   如前所述,目前使用最广泛的是混合的构造函数/原型方法.此外,动态原型方法也很流行,功能上和前者等价.可以采用上述方法中的一种.   实例:   1、利用javaScript的面向对象技术封装一个字符串连结的类.   传统的方式:   var str=“hellow”   str +=“world”   缺点:字符串的不变性,导致这种做法很没有效率   } 改进一   var Arr = new Array();   Arr[0]=“hellow”;   Arr[1]=“world”;   var str = Arr.join(““);   虽然解决了效率问题,但不太优雅.   } 改进二   function StringBuffer()   {   this._strings_=new Array(); //私用属性   }   StringBuffer.prototype.append = function(str)   {   this._strings_.push(str);   }   StringBuffer.prototype.toString=function(){ return this._strings_.join(“”); //join() 方法用于把数组中的所有元素放入一个字符串。   }   } //call 使用   } var strobj = new StringBuffer();   } strobj.append("hellow");   } strobj.append("world");   } alert(strobj.toString());   修改对象已有的属性,创建新方法   Eg1:   Number.prototype.toHexString=function()   {   return this.toString(16);   }   //call   var iNum=15;   alert(iNum.toHexString()); //output “f”   } Eg2 给array扩展3个方法   Array.prototype.enqueue=function(vItem)   {   this.push(vItem);//想对象添加值   }   Array.prototype.dequeue = function()   {   return this.shift();   shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值   }   Array.prototype.indexOf=function(vItem){   for(var i=0;i<this.length;i++)   {   if (vItem == this[i])   return i;   }   return -1;   }   } //call   } var arr = new Array();   } arr.enqueue("aaa");   } arr.enqueue("bbb");   } arr.enqueue("ccc");   } arr.dequeue();   } alert(arr.indexOf("aaa"));   Eg3.扩展Object   Object.prototype.alert = function()   {   alert(this.valueOf());   }   //call   var str=“hellow”;   var iNum = 25;   str.alert();   iNum.alert();   重定义已有方法   Function.prototype.toString = function(){   return “”; }   function sayHi(){   alert(“hi”); }   //call   alert(sayHi.toString()); //output “”
转载请注明原文地址: https://www.6miu.com/read-3350132.html

最新回复(0)