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

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

2011-10-26 11:18 323 查看
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 “”
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: