Bookmark and Share

Lee's 程序人生

HTML CSS Javascript XML AJAX ATLAS C# C++ 数据结构 软件工程 设计模式 asp.net Java 数字图象处理 Sql 数据库
  博客园  :: 首页  :: 新随笔  :: 联系 :: 管理

javascript定义类和对象

Posted on 2008-01-14 11:19  analyzer  阅读(1840)  评论(2编辑  收藏  举报
/用Emeditor 以js 方式显示更为美观

/* 宿主对象
所有非本地对象都是宿主对象(host object),即由ECMAScript 实现的宿主环境提供的对象。所有BOM
和DOM 对象都是宿主对象
作用域
任何程序设计语言的程序员都懂得作用域的概念,即某些变量的适用范围

公用、受保护和私有作用域
在传统的面向对象程序设计中,主要关注于公用和私有作用域。公用作用域中的对象属
性可以从对象外部访问,即开发者创建对象的实例后,就可使用它的公用属性。而私有作用
域中的属性只能在对象内部访问,即对于外部世界来说,这些属性并不存在。这也意味着如
果类定义了私有属性和方法,则它的子类也不能访问这些属性和方法。
最近,另一种作用域流行起来,即受保护作用域。虽然在不同语言中,受保护作用域的
应用的规则不同,但一般说来,它都用于定义私有的属性和方法,只是这些属性和方法还能
被其子类访问。
对ECMAScript 讨论这些作用域几乎毫无意义,因为ECMAScript 中只存在一种作用域—
—公用作用域。ECMAScript 中的所有对象的所有属性和方法都是公用的。因此,定义自己的
类和对象时,必须格外小心。记住,所有属性和方法默认都是公用的。
许多开发者都在网上提出了有效的属性作用域模式,解决了ECMAScript 的这种问题。由
于缺少私有作用域,开发者们制定了一个规约,说明哪些属性和方法应该被看作私有的。这
种规约规定在属性名前后加下划线
obj.__color__="red";
这段代码中,属性color 是私有的。记住,这些下划线并不改变这些属性是公用属性的事
实,它只是告诉其他开发者,应该把该属性看作私有的。
有些开发者还喜欢用单下划线说明私有成员

静态作用域并非静态的
静态作用域定义的属性和方法任何时候都能从同一个位置访问。在Java 中,类可具有静
态属性和方法,无需实例化该类的对象,即可访问这些属性和方法,例如java.net.URLEncoder
类,它的函数encode()即是静态方法。
严格说来,ECMAScript 并没有静态作用域。不过,它可以给构造函数提供属性和方法。
还记得吗,构造函数只是函数。函数是对象,对象可以有属性和方法

关键字this
在ECMAScript 中,要掌握的最重要的概念之一是关键字this 的用法,它用在对象的方法
中。关键字this 总是指向调用该方法的对象
那么为什么使用this 呢?因为在实例化对象时,总是不能确定开发者会使用什么样的变量
名。使用this,即可在任意多个地方重用同一个函数

如果不用对象或this 关键字引用变量,ECMAScript 就会把它看作局部变量或全局变量
*/

/*定义类和对象
使用预定义对象的能力只是面向对象语言的能力的一部分。真正的强大之处在于能够创
建自己专用的类和对象。与ECMAScript 中的许多特性一样,可以用各种方法实现这一点
*/

//原始方式
var ocar=new Object;
ocar.color="red";
ocar.doors=4;
ocar.mpg=23;
ocar.showcolor=function(){alert(this.color);}
//工厂方式
function createcar(){
var ocar=new Object;
ocar.color="red";
ocar.doors=4;
ocar.mpg=23;
ocar.showcolor=function(){alert(this.color);}
return ocar;
}
var ocar1=createcar();
var ocar2=createcar();
ocar1.showcolor();
//ocar1.color="blue";
//ocar1.showcolor();
ocar2.showcolor(); //不会变成blue


//带传入值

function createcar(incolor,indoors,inmpg){
var ocar=new Object;
ocar.color=incolor;
ocar.doors=indoors;
ocar.mpg=inmpg;
ocar.showcolor=function(){alert(this.color);}
return ocar;
}
var ocar1=createcar("yellow",4,20);
var ocar2=createcar();
ocar1.showcolor();
//ocar1.color="blue";
//ocar1.showcolor();
ocar2.showcolor(); //不会变成blue

/*
每次创建一个car对象都会重新创建一个showcolor()函数
从工厂方法外定义一个函数,然后通过属性指向该方法可以避免此问题
*/

function showcolor(){
alert(this.color);
}
function createcar(incolor,indoors,inmpg){
var ocar=new Object;
ocar.color=incolor;
ocar.doors=indoors;
ocar.mpg=inmpg;
ocar.showcolor=showcolor;
return ocar;
}
var ocar1=createcar("yellow",4,20);
ocar1.showcolor();

//构造函数方式

function car(incolor,indoors,inmpg){
this.color=incolor;
this.doors=indoors;
this.mpg=inmpg;
this.showcolor=function(){
alert(this.color);
}
}
var ocar1=new car("red",4,5);
var ocar2=new car("blue",3,4);
//和工厂函数一样,构造函数会重复生成函数,为每个对象都创建独立的函数版本。也可以用外部函数重写构造函数


// 原型方式,利用对象的prototype属性,可看成创建新对象所依赖的原型。用空构造函数来设置类名。然后所有的属和方法都被赋予prototype属性
function car(){
}
car.prototype.color="red";
car.prototype.doors=4;
car.prototype.mpg=20;
car.prototype.showcolor=function(){
alert(this.color);
};
var ocar1=new car();
var ocar2=new car();
/*
ocar1.showcolor();
ocar1.color="black"; //不会变black
car.prototype.color="green";
ocar1.showcolor(); //就会变了
ocar2.showcolor();
*/
//可以使用instanceof检查类型
/*
这个构造函数没有参数。使用原型方式时,不能通过给构造函数传递参数初始化
属性的值,因为ocar1 和ocar2 的color 属性都等于"red",doors 属性都等于4,mpg 属性都等于20。
这意味必须在对象创建后才能改变属性的默认值,这点很令人讨厌,但还不至于是世界末日。
真正的问题出现在属性指向的是对象,而不是函数时。函数共享不会造成任何问题,但对象
却很少被多个实例共享的。考虑下面的例子: */
function car(){
}
car.prototype.color="red";
car.prototype.doors=4;
car.prototype.mpg=20;
car.prototype.drivers=new Array("Mike","Sue");
car.prototype.showcolor=function(){
alert(this.color);
};
var ocar1=new car();
var ocar2=new car();
ocar1.color="blue";
ocar1.showcolor();
ocar2.showcolor();
ocar1.drivers.push("dd"); //后面所有的drivers都是三个值了
alert(ocar1.drivers);
alert(ocar2.drivers);

/*
原型生成出来的对象是按原型链来找值,如果本身没有就往上一级找。当ocar1 的color属性改掉了,
就等于是在ocar1对象本身添加了一个color属性而把父类继承给它的color属性给覆盖了。
而对ocar1的drivers数组属性进行了push操作的话,drivers实际上是一个array,也就是个引用值,会直接把引用给改掉。

这里,属性drivers 是指向Array 对象的指针,该数组中包含两个名字"Mike"和"Sue"。由于drivers
是引用值,Car 的两个实例都指向同一个数组。这意味着给ocar1.drivers 添加值"Matt",在ocar2.drivers
中也能看到。输出这两个指针中的任何一个,结果都是显示字符串"Mike,Sue,dd"。
由于创建对象时有这么多问题,你一定会想,是否有种合理的创建对象的方法呢?答案
是联合使用构造函数和原型方式。*/

//混合的构造函数/原型方式
/*
联合使用构造函数和原型方式,就可像用其他程序设计语言一样创建对象。这种概念非
常简单,即用构造函数定义对象的所有非函数属性,用原型方式定义对象的函数属性(方法)。
结果所有函数都只创建一次,而每个对象都具有自己的对象属性实例 */

function car(incolor,indoors,inmpg){
this.color=incolor;
this.doors=indoors;
this.mpg=inmpg;
this.drivers=new Array("Mike","Sue");
car.prototype.showcolor=function(){
alert(this.color);
};
}
var ocar1=new car();
var ocar2=new car();
ocar1.drivers.push("dd");
alert(ocar1.drivers);
alert(ocar2.drivers);

//动态原型法

/* Java 很好的打包了Car类的所有属性和方法,因此看见这段代码就知道它要实现什么功能,
它定义了一个对象的信息。批评混合的构造函数/原型方式的人认为,在构造函数内存找属性,
在其外部找方法的做法不合逻辑。因此,他们设计了动态原型方法,以提供更友好的编码风
格。
动态原型方法的基本想法与混合的构造函数/原型方式相同,即在构造函数内定义非函数
属性,而函数属性则利用原型属性定义。唯一的区别是赋予对象方法的位置 */

function car(incolor,indoors,inmpg){
this.color=incolor;
this.doors=indoors;
this.mpg=inmpg;
this.drivers=new Array("Mike","Sue");
if(typeof car._initialized=="undefined") {
car.prototype.showcolor=function() {
alert(this.color);
}
color._initialized=true;
}
}

/* 假设我们向重复抽取字符串的第三个字符,我们可以更改
String 对象的原型,以便所有的字符串都有我们定义的方法:
String.prototype.getThirdChar = function()
{
return this.charAt(2);
}
这样我们就可以在任何字符串对象中调用该方法了:
var c = "Example".getThirdChar(); // c 的值为 'a'
*/

//混合工厂方式
/*
这种方式通常是在不能应用前一种方式时的变通方法。它的目的是创建假构造函数,只
返回另一种对象的新实例。
只不过在创建时用 var car=new car();

由于在Car()构造函数内部调用了new 运算符,所以将忽略第二个new 运算符(位于构造函
数之外)。在构造函数内部创建的对象被传递回变量var。
这种方式在对象方法的内部管理方面与经典方式有着相同的问题。强烈建议:除非
万不得已 还是避免使用这种方式。
*/

/*
采用哪种方式
目前使用最广泛的是混合的构造函数/原型方式。此外,动态原型方法也很流
行,在功能上与构造函数/原型方式等价。可以采用这两种方式中的任何一种。不过不要单独
使用经典的构造函数或原型方式,因为这样会给代码引入问题

对象令人感兴趣的一点是用它们解决问题的方式。ECMAScript 中最常见的一个问题是字
符串连接的性能。与其他语言类似,ECMAScript 的字符串是不可变的,即它们的值不能改变
*/
var str="hello";
str+=" world!";

/* 实际上,这段代码在幕后执行的步骤如下:
(1) 创建存储"hello"的字符串。
(2) 创建存储"world"的字符串。
(3) 创建存储连接结果的字符串。
(4) 把str 的当前内容复制到结果中。
(5) 把"world"复制到结果中。
(6) 更新str,使它指向结果。
每次完成字符串连接都会执行步骤2 到6,使得这种操作非常消耗资源。如果重复这一过
程几百次,甚至几千次,就会造成性能问题。解决方法是用Array 对象存储字符串,然后用join()
方法(参数是空字符串)创建最后的字符串。 */

for(var i=0;i<99999;i++)
{
var str="hello";
str+=" world!";
document.write(str+"<br>");
}
alert("finish");
/* for(var i=0;i<99999;i++)
{
var arr=new Array();
arr[0]="hello";
arr[1]=" world!";
var str=arr.join("");
document.write(str+"<br>");
} */
 
我要啦免费统计