JavaScript中的面向对象编程(一)

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; //这时thisocar1

   

       var oCar2 = new Object();

       oCar2.Color = “blue”;

      oCar2.ShowColor=ShowColor; //这时thisocar2

       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.cnblogs.com/aqbyygyyga/p/2224942.html