ECMAScript对象是JavaScript比较特殊的特性之一,在JavaScript中,要记住一点,一切都是对象,包括我们前面所学的方法.本章的重点是如何操作及使用这些对象,以及如果创建自己的对象,以根据需要增加专用的功能.
ECMA-262把对象(Ojbect)定义为"属性的无序集合,每个属性存放一个原始值,对象或函数."严格来说,这意味着对象是无特定顺序的值的数组.
每个对象都由类定义,可以把类看作对象的配方,类不仅要定义对象的接口(属性和方法),还要定义对象的内部工作(使属性和方法发挥作用的代码).
面向对象语言的要求:
1.封装:把相关信息(数据或方法)存储在对象中的能力.
2.聚集:把一个对象存储在另一个对象内的能力.
3.继承:由另一个类(或多个类)得来类的属性和方法的能力.
4.多态:编写能以多种方法运行的函数或方法的能力.
ECMAScript支持这些要求,因此可以看作面向对象的.
在ECMAScript中,对象由特性构成,特性可以是原始值,也可以是引用值.如果特性存放的是函数,它将被看作是对象的方法,否则该特性被看作属性.
声明和实例化
var oObject = new Object();
var oStringObject = new String();
如果构造方法无参数,则括号不是必需的.
对象回收
ECMAScript有无用存储单元收集程序,意味着不必专门销毁对象来释放内存,当对象没有引用绑定时,称该对象被废除了.每个函数执行完它的代码,无用存储单元收集程序都会运行,释放所有的局部变量,还有在一些其它不可预知的情况下,无用存储单元收集程序也会运行.
把对象与null对象绑定,可以强制性的废除对象.
var oObject = new Ojbect();
oObject = null;
每用完一个对象后,就将其废除,来释放内存,是个好习惯.
废除对象的所有引用时要当心,如果一个对象有两个或更多引用,则要正确废除该对象,必须将其所有的引用都设置为null
ECMAScript的封装
对ECMAScript来说,作用域的讨论几乎毫无意义,因为ECMAScript中只存在一种作用域,公用作用域,所有对象的所有属性和方法都是公用的,因此,定义自己的类和对象,必须格外小心,记住,所有属性和方法默认都是公用的.
ECMAScript由于缺少私有作用域,开发者们制定了一个规约,说明哪些属性和方法应该被看作私有的,这种规约规定在属性名前后加上下划线,如:obj._color_ = "red",这段代码告诉我们属性color是私有的,但是下划线并不改变这些属性是公用属性的事实,它只是告诉其他开发者,应该把该属性看作是私有的.
关键字this
ECMAScript中,this总是指向调用该方法的对象.例如:
var oCar = new Object();
oCar.color = "red";
oCar.showColor = function(){
alert(this.color);
}
这里,关键字this用在对象的showColor方法中,在此环境中,this等于oCar,下面的代码与上面的代码功能相同:
var oCar = new Object();
oCar.color = "red";
oCar.showColor = function(){
alert(oCar.color);
}
考虑下面的示例:
function showColor(){
alert(this.color);
}
var oCar1 = new Object();
oCar1.color = "red";
oCar1.showColor = showColor;
var oCar2 = new Object();
oCar2.color = "blue";
oCar2.showColor = showColor;
oCar1.showColor();
oCar2.showColor();
注意引用对象的属性时,必须使用this关键字,例如,下面的showColor方法不能运行.
function showColor(){
alert(color);
}
工厂模式
由于对象的属性可以在对象创建后动态定义,所以许多开发都在初次学习类时,会像上面那样创建对象.这样问题就出来了,如果要创建多个car实例呢,怎么办呢?解决方法工厂模式,请看下面的代码:
function createCar(){
var oTempCar = new Object();
oTempCar.color = "red";
oTempCar.showColor = function(){
alert(this.color);
}
return oTempCar;
}
var oCar1 = createCar();
var oCar2 = createCar();
这样做,有个毛病,就是两个对象的属性完全一样,没有关系,加参数列表,传递各个属性的值.改为:
function createCar(sColor){
var oTempCar = new Object();
oTempCar.color = sColor;
oTempCar.showColor = function(){
alert(this.color);
}
return oTempCar;
}
var oCar1 = createCar("red");
var oCar2 = createCar("blue");
这时可以看到两个对象具有相同的属性,却有不同的属性值.
前面的例子中,每次调用函数createCar()都要创建新函数showColor(),意味着每个对象都有自己的showColor()版本,事实上,每个对象应该共享同一个函数.
解决方法:在工厂方法外定义对象的方法,然后通过属性指向该方法.从而避开这个问题,请看下面的代码:
function showColor(){
alert(this.color);
}
function createCar(sColor){
var oTempCar = new Object();
oTempCar.color = sColor;
oTempCar.showColor = showColor;
return oTempCar;
}
var oCar1 = createCar("red");
var oCar2 = createCar("blue");
oCar1.showColor();
oCar2.showColor();
虽然这样做,解决了重要创建函数对象的问题,但该函数看起来不像对象的方法.所有这些问题引发了开发者定义的构造函数的出现.
构造函数方式
创建构造函数就像定义工厂函数一样,定义构造函数名时,根据习惯,首字母大写,以使它与其它的普通方法区分开来.
function Car(sColor){
this.color = sColor;
this.showColor = function(){
alert(this.color);
}
}
var oCar1 = new Car("red");
var oCar2 = new Car("blue");
与前面的差别:构造函数内部无创建对象,而是使用this关键字.
现在用new运算符和类名Car创建对象,就更像创建ECMAScript中一般对象了,但是构造函数会重复生成函数,为每个对象都创建独立的函数版本,不过,与工厂函数相似,也可以用外部函数重写构造函数.
function showColor(){
alert(this.color);
}
function Car(sColor){
this.color = sColor;
this.showColor = showColor;
}
var oCar1 = new Car("red");
var oCar2 = new Car("blue");
更好解决方案:原型方式
原型方式
上面的代码虽然已经实现了类的功能,并且每个对象有自己单独的属性,方法所有的对象共用,但写法却非常不优雅,showColor()方法感觉有点像一个单独的方法,和Car类没有什么固定的关系.
原型对象,大家可以理解为Java中的Class Car{...},也就是类定义的原型代码,定义好构造函数后,JavaScript会自动创建构造函数对应的原型对象,每个构造方法都有一个prototype属性,该属性返回原型对象的引用,我们可以让原型对象绑定类所拥有的方法,让其整个架构看起来更像面向对象的语义.
请看下面的代码:
function Car(sColor){
this.color = sColor;
}
Car.prototype.showColor = function(){
alert(this.color);
}
var oCar1 = new Car("red");
oCar1.showColor();
现在看起来就更像创建一般对象了.这也是现在JS中最流行的创建对象的方式,有个规定,构造函数中规定属性值,方法一律在外面用原型的方式添加.
instanceof 运算符:判断对象的类型
function MyObject(){
}
alert(oCar1 instanceof Car);
alert(oCar1 instanceof MyObject);
修改内置对象
在ECMAScript中,每个本地对象也有用法完全相同的prototype属性.比如,JS中,String类没有提供trim()方法,Java中此方法可以截取字符串两端的空格,那么我们怎么样在JS中创建此方法呢?
String.prototype.trim = function(){
return this.replace(/(^ +)|( +$)/g,"");
}
var str = " AAA ";
alert(str.length);
alert(str.trim().length);
创建自己的实用工具类
StringBuffer类,Java中是字符串缓冲类,具有较高的连接效率,我们在JS中怎么实现这个类呢.比如我们要执行一个字符串的连接操作,如果用+号进行连接,会造成生成许多临时字符串,这样非常消耗资源,会造成性能问题.最好的解决方法是用Array对象存储字符串,然后用join()方法(参数为空字符串"")创建最后的字符串.
function StringBuffer(){
this._strings_ = new Array();
}
StringBuffer.prototype.append = function(str){
this._strings_.push(str);
}
StringBuffer.prototype.toString = function(){
this._strings_.join("");
}
var d1 = new Date();
var str = "";
for(var i=0; i<1000000; i++ ){
str += "text";
}
var d2 = new Date();
document.write("连+所用时长:" + (d2.getTime() - d1.getTime()) + "毫秒");
document.write("<BR><BR>");
var oBuffer = new StringBuffer();
d1 = new Date();
for(var i=0; i<1000000; i++ ){
oBuffer.append("text");
}
d2 = new Date();
document.write("StringBuffer所用时长:" + (d2.getTime() - d1.getTime()) + "毫秒");
经过测试,怪事发生了,竟然StringBuffer效率要低200%以上.
目标
1.对象的介绍
2.创建对象
3.对象的属性
4.对象的构造函数
5.对象的方法
6.Object对象
对象的理解:它是一种复杂的数据类型,也是一个工具,它能够保存数据,也可以处理数据.
对象创建的三种方法:
1.对象直接量
2.设置属性法
3.构造函数(推荐方式)
[size=large]对象直接量[/size]
var circle = { x:0, y:0, radius:2 }
document.write(circle.x);
document.write(circle.y);
document.write(circle.radius);
--------------------------------------------------------------------
var homer = {
name: "Homer Simpson",
age: 34,
married: true,
occupation: "plant operator",
email: "homer@simpsons.com"
};
document.write(homer.name + "<BR />");
document.write(homer.age + "<BR />");
document.write(homer.married + "<BR />");
document.write(homer.occupation + "<BR />");
document.write(homer.email + "<BR />");
[size=large]设置属性法[/size]
var book = new Object(); //创建一个book对象
book.title = "JavaScript: The Definitive Guide";//给book对象添加一个属性
book.chapter1 = new Object(); //给book对象添加一个chapter1的属性,并且此属性也是对象
book.chapter1.title = "Introduction to JavaScript";//给book.chapter1添加属性
book.chapter1.pages = 19;//给book.chapter1添加属性
//给book对象添加一个chapter2的属性,并且此属性也是对象(对象直接量方式)
book.chapter2 = { title: "Lexical Structure", pages: 6 };
document.write("Outline: " + book.title + "<BR/>" +
"Chapter 1 " + book.chapter1.title + "<BR/>" +
"Chapter 2 " + book.chapter2.title);
[size=large]
[size=large]构造函数[/size]
function Rectangle(w, h){
this.width = w;
this.height = h;
}
var rect1 = new Rectangle(2, 4);
var rect2 = new Rectangle(8.5, 11);
document.write(rect1.width + "," + rect1.height + "<BR />");
document.write(rect2.width + "," + rect2.height + "<BR />");
[size=large]属性的枚举[/size]
function DisplayPropertyNames(obj) {
for(var name in obj){
document.write(name + "<BR />");
}
}
function Rectangle(w, h){
this.width = w;
this.height = h;
}
var rect1 = new Rectangle(2, 4);
DisplayPropertyNames(book);
[size=large]属性的删除[/size]
function DisplayPropertyNames(obj) {
for(var name in obj){
document.write(name + "<BR />");
}
}
function Rectangle(w, h){
this.width = w;
this.height = h;
}
var rect1 = new Rectangle(2, 4);
delete rect1.width;
DisplayPropertyNames(rect1);
[size=large]给对象添加方法[/size]
//先准备好方法,注意这里用到了this关键字
function Rectangle_area( ) { return this.width * this.height; }
function Rectangle_setSize(w,h) { this.width = w; this.height = h; }
function Rectangle(w, h){
this.width = w;
this.height = h;
//添加方法,将方法绑定到属性上
this.area = Rectangle_area;
this.setSize = Rectangle_setSize;
}
var rect1 = new Rectangle(2, 4);
document.write(rect1.area() + "<BR />");
rect1.setSize(20,40);
document.write(rect1.area());
[size=large]构造函数创建对象的缺点[/size]
用构造函数把方法赋予它要初始化的对象,效率非常低,如果我们这样做,那么构造函数创建的每一个对象都会有相同的方法属性的副本。
我们的目标是:类所声明的方法,常量能够被所有的对象共享。
解决方法:原型对象和继承
[size=large]原型方式[/size]
上面的代码虽然已经实现了类的功能,并且每个对象有自己单独的属性,方法所有的对象共用,但写法却非常不优雅,showColor()方法感觉有点像一个单独的方法,和Car类没有什么固定的关系.
原型对象,大家可以理解为Java中的Class Car{...},也就是类定义的原型代码,定义好构造函数后,JavaScript会自动创建构造函数对应的原型对象,每个构造方法都有一个prototype属性,该属性返回原型对象的引用,我们可以让原型对象绑定类所拥有的方法,让其整个架构看起来更像面向对象的语义.
请看下面的代码:
function Car(sColor){
this.color = sColor;
}
Car.prototype.showColor = function(){
alert(this.color);
}
var oCar1 = new Car("red");
oCar1.showColor();
现在看起来就更像创建一般对象了.这也是现在JS中最流行的创建对象的方式,有个规定,构造函数中规定属性值,方法一律在外面用原型的方式添加.
修改内置对象
在ECMAScript中,每个本地对象也有用法完全相同的prototype属性.比如,JS中,String类没有提供trim()方法,Java中此方法可以截取字符串两端的空格,那么我们怎么样在JS中创建此方法呢?
String.prototype.trim = function(){
return this.replace(/(^ +)|( +$)/g,"");
}
var str = " AAA ";
alert(str.length);
alert(str.trim().length);
创建自己的实用工具类
StringBuffer类,Java中是字符串缓冲类,具有较高的连接效率,我们在JS中怎么实现这个类呢.比如我们要执行一个字符串的连接操作,如果用+号进行连接,会造成生成许多临时字符串,这样非常消耗资源,会造成性能问题.最好的解决方法是用Array对象存储字符串,然后用join()方法(参数为空字符串"")创建最后的字符串.
function StringBuffer(){
this._strings_ = new Array();
}
StringBuffer.prototype.append = function(str){
this._strings_.push(str);
}
StringBuffer.prototype.toString = function(){
this._strings_.join("");
}
var d1 = new Date();
var str = "";
for(var i=0; i<10000; i++ ){
str += "text";
}
var d2 = new Date();
document.write("连+所用时长:" + (d2.getTime() - d1.getTime()) + "毫秒");
document.write("<BR><BR>");
var oBuffer = new StringBuffer();
d1 = new Date();
for(var i=0; i<10000; i++ ){
oBuffer.append("text");
}
d2 = new Date();
document.write("StringBuffer所用时长:" + (d2.getTime() - d1.getTime()) + "毫秒");
经过测试,怪事发生了,竟然StringBuffer效率要低200%以上.
ECMA-262把对象(Ojbect)定义为"属性的无序集合,每个属性存放一个原始值,对象或函数."严格来说,这意味着对象是无特定顺序的值的数组.
每个对象都由类定义,可以把类看作对象的配方,类不仅要定义对象的接口(属性和方法),还要定义对象的内部工作(使属性和方法发挥作用的代码).
面向对象语言的要求:
1.封装:把相关信息(数据或方法)存储在对象中的能力.
2.聚集:把一个对象存储在另一个对象内的能力.
3.继承:由另一个类(或多个类)得来类的属性和方法的能力.
4.多态:编写能以多种方法运行的函数或方法的能力.
ECMAScript支持这些要求,因此可以看作面向对象的.
在ECMAScript中,对象由特性构成,特性可以是原始值,也可以是引用值.如果特性存放的是函数,它将被看作是对象的方法,否则该特性被看作属性.
声明和实例化
var oObject = new Object();
var oStringObject = new String();
如果构造方法无参数,则括号不是必需的.
对象回收
ECMAScript有无用存储单元收集程序,意味着不必专门销毁对象来释放内存,当对象没有引用绑定时,称该对象被废除了.每个函数执行完它的代码,无用存储单元收集程序都会运行,释放所有的局部变量,还有在一些其它不可预知的情况下,无用存储单元收集程序也会运行.
把对象与null对象绑定,可以强制性的废除对象.
var oObject = new Ojbect();
oObject = null;
每用完一个对象后,就将其废除,来释放内存,是个好习惯.
废除对象的所有引用时要当心,如果一个对象有两个或更多引用,则要正确废除该对象,必须将其所有的引用都设置为null
ECMAScript的封装
对ECMAScript来说,作用域的讨论几乎毫无意义,因为ECMAScript中只存在一种作用域,公用作用域,所有对象的所有属性和方法都是公用的,因此,定义自己的类和对象,必须格外小心,记住,所有属性和方法默认都是公用的.
ECMAScript由于缺少私有作用域,开发者们制定了一个规约,说明哪些属性和方法应该被看作私有的,这种规约规定在属性名前后加上下划线,如:obj._color_ = "red",这段代码告诉我们属性color是私有的,但是下划线并不改变这些属性是公用属性的事实,它只是告诉其他开发者,应该把该属性看作是私有的.
关键字this
ECMAScript中,this总是指向调用该方法的对象.例如:
var oCar = new Object();
oCar.color = "red";
oCar.showColor = function(){
alert(this.color);
}
这里,关键字this用在对象的showColor方法中,在此环境中,this等于oCar,下面的代码与上面的代码功能相同:
var oCar = new Object();
oCar.color = "red";
oCar.showColor = function(){
alert(oCar.color);
}
考虑下面的示例:
function showColor(){
alert(this.color);
}
var oCar1 = new Object();
oCar1.color = "red";
oCar1.showColor = showColor;
var oCar2 = new Object();
oCar2.color = "blue";
oCar2.showColor = showColor;
oCar1.showColor();
oCar2.showColor();
注意引用对象的属性时,必须使用this关键字,例如,下面的showColor方法不能运行.
function showColor(){
alert(color);
}
工厂模式
由于对象的属性可以在对象创建后动态定义,所以许多开发都在初次学习类时,会像上面那样创建对象.这样问题就出来了,如果要创建多个car实例呢,怎么办呢?解决方法工厂模式,请看下面的代码:
function createCar(){
var oTempCar = new Object();
oTempCar.color = "red";
oTempCar.showColor = function(){
alert(this.color);
}
return oTempCar;
}
var oCar1 = createCar();
var oCar2 = createCar();
这样做,有个毛病,就是两个对象的属性完全一样,没有关系,加参数列表,传递各个属性的值.改为:
function createCar(sColor){
var oTempCar = new Object();
oTempCar.color = sColor;
oTempCar.showColor = function(){
alert(this.color);
}
return oTempCar;
}
var oCar1 = createCar("red");
var oCar2 = createCar("blue");
这时可以看到两个对象具有相同的属性,却有不同的属性值.
前面的例子中,每次调用函数createCar()都要创建新函数showColor(),意味着每个对象都有自己的showColor()版本,事实上,每个对象应该共享同一个函数.
解决方法:在工厂方法外定义对象的方法,然后通过属性指向该方法.从而避开这个问题,请看下面的代码:
function showColor(){
alert(this.color);
}
function createCar(sColor){
var oTempCar = new Object();
oTempCar.color = sColor;
oTempCar.showColor = showColor;
return oTempCar;
}
var oCar1 = createCar("red");
var oCar2 = createCar("blue");
oCar1.showColor();
oCar2.showColor();
虽然这样做,解决了重要创建函数对象的问题,但该函数看起来不像对象的方法.所有这些问题引发了开发者定义的构造函数的出现.
构造函数方式
创建构造函数就像定义工厂函数一样,定义构造函数名时,根据习惯,首字母大写,以使它与其它的普通方法区分开来.
function Car(sColor){
this.color = sColor;
this.showColor = function(){
alert(this.color);
}
}
var oCar1 = new Car("red");
var oCar2 = new Car("blue");
与前面的差别:构造函数内部无创建对象,而是使用this关键字.
现在用new运算符和类名Car创建对象,就更像创建ECMAScript中一般对象了,但是构造函数会重复生成函数,为每个对象都创建独立的函数版本,不过,与工厂函数相似,也可以用外部函数重写构造函数.
function showColor(){
alert(this.color);
}
function Car(sColor){
this.color = sColor;
this.showColor = showColor;
}
var oCar1 = new Car("red");
var oCar2 = new Car("blue");
更好解决方案:原型方式
原型方式
上面的代码虽然已经实现了类的功能,并且每个对象有自己单独的属性,方法所有的对象共用,但写法却非常不优雅,showColor()方法感觉有点像一个单独的方法,和Car类没有什么固定的关系.
原型对象,大家可以理解为Java中的Class Car{...},也就是类定义的原型代码,定义好构造函数后,JavaScript会自动创建构造函数对应的原型对象,每个构造方法都有一个prototype属性,该属性返回原型对象的引用,我们可以让原型对象绑定类所拥有的方法,让其整个架构看起来更像面向对象的语义.
请看下面的代码:
function Car(sColor){
this.color = sColor;
}
Car.prototype.showColor = function(){
alert(this.color);
}
var oCar1 = new Car("red");
oCar1.showColor();
现在看起来就更像创建一般对象了.这也是现在JS中最流行的创建对象的方式,有个规定,构造函数中规定属性值,方法一律在外面用原型的方式添加.
instanceof 运算符:判断对象的类型
function MyObject(){
}
alert(oCar1 instanceof Car);
alert(oCar1 instanceof MyObject);
修改内置对象
在ECMAScript中,每个本地对象也有用法完全相同的prototype属性.比如,JS中,String类没有提供trim()方法,Java中此方法可以截取字符串两端的空格,那么我们怎么样在JS中创建此方法呢?
String.prototype.trim = function(){
return this.replace(/(^ +)|( +$)/g,"");
}
var str = " AAA ";
alert(str.length);
alert(str.trim().length);
创建自己的实用工具类
StringBuffer类,Java中是字符串缓冲类,具有较高的连接效率,我们在JS中怎么实现这个类呢.比如我们要执行一个字符串的连接操作,如果用+号进行连接,会造成生成许多临时字符串,这样非常消耗资源,会造成性能问题.最好的解决方法是用Array对象存储字符串,然后用join()方法(参数为空字符串"")创建最后的字符串.
function StringBuffer(){
this._strings_ = new Array();
}
StringBuffer.prototype.append = function(str){
this._strings_.push(str);
}
StringBuffer.prototype.toString = function(){
this._strings_.join("");
}
var d1 = new Date();
var str = "";
for(var i=0; i<1000000; i++ ){
str += "text";
}
var d2 = new Date();
document.write("连+所用时长:" + (d2.getTime() - d1.getTime()) + "毫秒");
document.write("<BR><BR>");
var oBuffer = new StringBuffer();
d1 = new Date();
for(var i=0; i<1000000; i++ ){
oBuffer.append("text");
}
d2 = new Date();
document.write("StringBuffer所用时长:" + (d2.getTime() - d1.getTime()) + "毫秒");
经过测试,怪事发生了,竟然StringBuffer效率要低200%以上.
目标
1.对象的介绍
2.创建对象
3.对象的属性
4.对象的构造函数
5.对象的方法
6.Object对象
对象的理解:它是一种复杂的数据类型,也是一个工具,它能够保存数据,也可以处理数据.
对象创建的三种方法:
1.对象直接量
2.设置属性法
3.构造函数(推荐方式)
[size=large]对象直接量[/size]
var circle = { x:0, y:0, radius:2 }
document.write(circle.x);
document.write(circle.y);
document.write(circle.radius);
--------------------------------------------------------------------
var homer = {
name: "Homer Simpson",
age: 34,
married: true,
occupation: "plant operator",
email: "homer@simpsons.com"
};
document.write(homer.name + "<BR />");
document.write(homer.age + "<BR />");
document.write(homer.married + "<BR />");
document.write(homer.occupation + "<BR />");
document.write(homer.email + "<BR />");
[size=large]设置属性法[/size]
var book = new Object(); //创建一个book对象
book.title = "JavaScript: The Definitive Guide";//给book对象添加一个属性
book.chapter1 = new Object(); //给book对象添加一个chapter1的属性,并且此属性也是对象
book.chapter1.title = "Introduction to JavaScript";//给book.chapter1添加属性
book.chapter1.pages = 19;//给book.chapter1添加属性
//给book对象添加一个chapter2的属性,并且此属性也是对象(对象直接量方式)
book.chapter2 = { title: "Lexical Structure", pages: 6 };
document.write("Outline: " + book.title + "<BR/>" +
"Chapter 1 " + book.chapter1.title + "<BR/>" +
"Chapter 2 " + book.chapter2.title);
[size=large]
[size=large]构造函数[/size]
function Rectangle(w, h){
this.width = w;
this.height = h;
}
var rect1 = new Rectangle(2, 4);
var rect2 = new Rectangle(8.5, 11);
document.write(rect1.width + "," + rect1.height + "<BR />");
document.write(rect2.width + "," + rect2.height + "<BR />");
[size=large]属性的枚举[/size]
function DisplayPropertyNames(obj) {
for(var name in obj){
document.write(name + "<BR />");
}
}
function Rectangle(w, h){
this.width = w;
this.height = h;
}
var rect1 = new Rectangle(2, 4);
DisplayPropertyNames(book);
[size=large]属性的删除[/size]
function DisplayPropertyNames(obj) {
for(var name in obj){
document.write(name + "<BR />");
}
}
function Rectangle(w, h){
this.width = w;
this.height = h;
}
var rect1 = new Rectangle(2, 4);
delete rect1.width;
DisplayPropertyNames(rect1);
[size=large]给对象添加方法[/size]
//先准备好方法,注意这里用到了this关键字
function Rectangle_area( ) { return this.width * this.height; }
function Rectangle_setSize(w,h) { this.width = w; this.height = h; }
function Rectangle(w, h){
this.width = w;
this.height = h;
//添加方法,将方法绑定到属性上
this.area = Rectangle_area;
this.setSize = Rectangle_setSize;
}
var rect1 = new Rectangle(2, 4);
document.write(rect1.area() + "<BR />");
rect1.setSize(20,40);
document.write(rect1.area());
[size=large]构造函数创建对象的缺点[/size]
用构造函数把方法赋予它要初始化的对象,效率非常低,如果我们这样做,那么构造函数创建的每一个对象都会有相同的方法属性的副本。
我们的目标是:类所声明的方法,常量能够被所有的对象共享。
解决方法:原型对象和继承
[size=large]原型方式[/size]
上面的代码虽然已经实现了类的功能,并且每个对象有自己单独的属性,方法所有的对象共用,但写法却非常不优雅,showColor()方法感觉有点像一个单独的方法,和Car类没有什么固定的关系.
原型对象,大家可以理解为Java中的Class Car{...},也就是类定义的原型代码,定义好构造函数后,JavaScript会自动创建构造函数对应的原型对象,每个构造方法都有一个prototype属性,该属性返回原型对象的引用,我们可以让原型对象绑定类所拥有的方法,让其整个架构看起来更像面向对象的语义.
请看下面的代码:
function Car(sColor){
this.color = sColor;
}
Car.prototype.showColor = function(){
alert(this.color);
}
var oCar1 = new Car("red");
oCar1.showColor();
现在看起来就更像创建一般对象了.这也是现在JS中最流行的创建对象的方式,有个规定,构造函数中规定属性值,方法一律在外面用原型的方式添加.
修改内置对象
在ECMAScript中,每个本地对象也有用法完全相同的prototype属性.比如,JS中,String类没有提供trim()方法,Java中此方法可以截取字符串两端的空格,那么我们怎么样在JS中创建此方法呢?
String.prototype.trim = function(){
return this.replace(/(^ +)|( +$)/g,"");
}
var str = " AAA ";
alert(str.length);
alert(str.trim().length);
创建自己的实用工具类
StringBuffer类,Java中是字符串缓冲类,具有较高的连接效率,我们在JS中怎么实现这个类呢.比如我们要执行一个字符串的连接操作,如果用+号进行连接,会造成生成许多临时字符串,这样非常消耗资源,会造成性能问题.最好的解决方法是用Array对象存储字符串,然后用join()方法(参数为空字符串"")创建最后的字符串.
function StringBuffer(){
this._strings_ = new Array();
}
StringBuffer.prototype.append = function(str){
this._strings_.push(str);
}
StringBuffer.prototype.toString = function(){
this._strings_.join("");
}
var d1 = new Date();
var str = "";
for(var i=0; i<10000; i++ ){
str += "text";
}
var d2 = new Date();
document.write("连+所用时长:" + (d2.getTime() - d1.getTime()) + "毫秒");
document.write("<BR><BR>");
var oBuffer = new StringBuffer();
d1 = new Date();
for(var i=0; i<10000; i++ ){
oBuffer.append("text");
}
d2 = new Date();
document.write("StringBuffer所用时长:" + (d2.getTime() - d1.getTime()) + "毫秒");
经过测试,怪事发生了,竟然StringBuffer效率要低200%以上.