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


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 “”

猜你喜欢

转载自gy421gy.iteye.com/blog/1359618