对象基础
一、ECMA-262面向对象术语
1.对象(object):属性的无序集合,每个属性存放一个原始值、对象或函数
2.类是对象的配方(对象定义),不仅要定义对象的接口(interface)(开发者访问的属性和
方法),还要定义对象的内部工作(使属性和方法发挥作用的代码)。
3.编译器和解释程序都根据类的说明构建对象,生成的对象叫做类的实例(instance)其
过程叫实例化(instantiation).对象定义存放在构造函数——用于创建对象的常规函数。
4.面向对象语言的要求
1)封装——把相关的信息(无论数据或方法)存储在对象中的能力。
2)聚集——把一个对象存储在另一个对象内的能力
3)继承——由另一个类(或多个类)得来类的属性和方法的能力。
4)多态——编写能以多种方式运行的函数或方法的能力。
5.对象由特性(attribute)构成,特性可以是原始值,也可以是引用值。如果特性存放的
是函数,它将被看作对象的方法(method),否则该特性被看做属性(property)。
二、对象应用
1.声明和实例化
var oObject=new Object()
var oObject=new Object //若构造函数无参数,括号可以省略
2.对象废除(dereference)
oObject=null //把对象的所有引用都设置为null,可以强制性的废除对象。
3.所有变量都采用晚绑定(late binding)方法,与C#,Java等早绑定(early binding)区别
三、本地对象
本地对象(native object):独立于宿主环境的ECMAScript实现提供的对象。
本地对象实际上就是ECMA-262定义的类(引用类型)。它们包括:
Object Function Array String Boolean
Number Date RegExp Error EvalError
RangeError ReferenceError SyntaxError TypeError URLError
1.Array类
var aValues1=new Array(), aValues2=new Array(20); //20是数组大小
var aColors=new Array();
aColors[0]="red", aColors[1]="green", aColors[2]="blue";//动态添加数组项
var aColors=new Array("red","green","blue"); //可参数声明值
alert(aColors[1]); //outputs "green"
aColors[9]="purple";
//数组可以根据需要来增大或减小,其中3到8的位置都添上值null
alert(aColors.length); //outputs "10"
var aColors=["red","green","blue"]; //字面量定义Array,跟传统定义相同
alert(aColors.toString()); //outputs "red,green,blue"
alert(aColors.valueOf()); //outputs "red,green,blue"
alert(aColors.toLocaleString()); //outputs "red,green,blue" 组合每一项的toLocaleString()
alert(aColors.join("-")); //outputs "red-green-blue" join()可采用任何字符串做分隔符
var sColors="red,green,blue";
var aColors=sColors.split(","); //split()方法把字符串转换为Array对象,参数为分隔符。
//split()如果把空字符串声明为分隔符,那返回的数组中每个项是字符串的字符。
var aColors2=aColor.concat("yellow","purple");//equal "red,green,blue,yellow,purple"
var aColors3=aColors2.slice(1,3);//equal "green,blue" slice()只返回后一个位置之前的项
var vItem=aColors.pop(); //equal "blue"
alert(aColors.valueOf()); //outputs "red,green"
aColors.push("yellow");
alert(aColors.toString()); //outputs "red,green,yellow"
var vItem=aColors.shift(); //equal "red" shift()用来移除数组的第一项
aColors.unShift("black"); //unShift()把一个项放在数组的第一项,其他依次后移
alert(aColors.toString()); //outputs "black,green,yellow"
//通过pop()和push()方法,使Array具有堆栈(stack)行为,后进先出(LIFO)结构。
//通过shift()和push()方法,使Array具有队列(queue)行为,后进后出(LILO)结。
aColors.reverse(); //reverse()方法用来颠倒数组项的顺序
alert(aColors.toString()); //outputs "yellow,green,black"
var afigure=[3,32,2,5];
afigure.sort(); //sort()方法用来根据数组各项的toString()值对数组项进行升序排序
alert(afigure.toString()); //outputs "2,3,32,5"
afigure.splice(0,2);//删除数组afigure的前两项
afigure.splice(2,0,4,6);//在位置2处插入4和6
afigure.splice(2,1,7,8);//删除在位置2的项,在位置2处插入7和8
2.Date类
ECMAScript把日期存储为距离UTC时间1970年1月1日凌晨12点的毫秒数。
var d=new Date();
var d=new Date(0);//设置日期和时间的值方式一,只声明距离上面的UTC的毫秒数
var d=new Date(Date.parse("May 25,2004"));/*parse()方法可将字符串转换成毫秒数
parse()除了mmmm dd,yyyy格式外,还支持mm/dd/yyyy等其他日期格式字符串
若pasre()方法的字符串不能转换成日期,整个函数返回NaN */
var d=new Date(Date.UTC(2004,1,5));/*UTC()方法参数为日期中的年和月(必须声明)
及其他可选参数:日、小时、分、秒和毫秒。注意月份值是0-11*/
var d=new Date(2004,1,4,13,15,32);//设置Date值方式二,直接声明UTC()可用的参数
alert(d.toString());//outputs "Wed Fed 4 13:15:32 UTC+0800 2004" 返回实现特定字符串
alert(d.valueOf()): //outputs "1075871732000" 返回日期的毫秒表示
alert(d.toDateString()); //outputs "Web Fed 4 2004" 返回实现特定格式的日期部分
alert(d.toTimeString()); //outputs "13:15:32 UTC+0800" 返回实现特定格式的时间部分
alert(d.toLocaleString()); //outputs "2004年2月4日 星期三 13:15:32" 区域特定格式
alert(d.toLocaleDateString()); //outputs "2004年2月4日 星期三" 区域特定日期部分
alert(d.toLocaleTimeString()); //outputs "13:15:32" 区域特定时间部分
alert(d.UTCString()); //outputs "web, 4 Feb 2004 05:15:32 UTC" 返回世界标准时间
alert(d.getTimezoneOffset()); //outputs "-480" 返回当前时区比UTC提前或落后的分种数
var d1=new Date(2004,0,1);
var d2=new Date(2004,6,1);
var bSupportsDaylightSavingTime=d1.getTimezoneOffset()!=d2.getTimezoneOffset();
//比较一年中春夏时间的时区偏移量,如果分钟不等,则该时区使用的是夏令时
d.setTime(1075999992000); //设置日期的毫秒表示
alert(d.toLocaleString()); //outputs "2004年2月6日 星期五 0:53:12"
alert(d.getTime()); //outputs "1075999992000" 返回日期的毫秒表示
d.setFullYear(2008); //设置日期的年份,参数必须是四位数字的年份值
alert(d.getFullYear()); //outputs "2008" 返回用四位数值表示的年份值
d.setUTCFullYear(2009); //设置UTC日期的年份
alert(d.getUTCFullYear()); //outputs "2009" 返回UTC日期的年份
其他对日期其他部分的获取和设置跟年份获取和设置大同小异。
月 getMonth() getUTCMonth() setMonth(month) setUTCMont(month)
日 getDate() getUTCDate() setDate(date) setUTCDate(date)
星期 getDay() getUTCDay() setDay(day) setUTCDay(day)
小时 getHours() getUTCHours() setHours(hours) setUTCHours(hours)
分钟 getMinutes() getUTCMinutes() setMinutes(minutes) setUTCMinutes(minutes)
秒 getSeconds() getUTCSeconds() setSeconds(seconds) setUTCSeconds(seconds)
毫秒 getMilliseconds() getUTCMilliseconds() setM...ds(Milliseconds) setUT...ds(Mil...ds)
四、内置对象
内置对象(built-in object)是由ECMAScript实现提供的、独立于宿主环境的所有对象,
在ECMAScript程序开始执行时出现。意味开发者不用实例化它们,它们已经被实例
化了。ECMA-262只定义两个内置对象,Global和Math,内置对象也都是本地对象。
1.Global对象
1)属性
如一些特殊值undefined、NaN、Infinity等,此外所有本地对象的构造函数也都是
Global对象的属性:Object、Array、Function、Boolean、String、Number、Date、
RegExp、Error、EvalError、RangeError、RefrenceError、SytaxError、TypeError、
URIError等。
2)方法
Global是很特别的对象,实际上他不存在,如:var pointer=Global 将报错,貌似独立
存在的函数,例如isNaN()、isFinite()、parseInt()、parseFloat()等等都是Global的方法
原因是在ECMAScript中,不存在独立的函数,所有函数必须是某个对象的方法。
encodeURI()和encodeURIComponent()用来编码传递给浏览器的URI(统一资源标识符)
encodeURI()用来处理完整的URI,而不对URI中的特殊字符进行编码,如冒号、前斜
杠、问号和英镑符号等。
encodeURIComponent()用于处理URI的一个片段,对它发现的所有非标准字符进行编码
var sUri="httptest://www.163.com/A B.htm#ha&ha"
alert(encodeURI(sUri)); //outputs "httptest://www.163.com/A%20B.htm#ha&ha"
alert(encodeURIComponent(sUri));
//outputs "httptest%3A%2F%2Fwww.163.com%2FA%20B.htm%23ha%26ha"
decodeURI()和decodeURIComponent()用于对编码的字符进行解码。区分与上面相同
以上四个URI方法可完全代替BOM的escape()和unescape()方法,推荐使用。
eval()方法用于把字符串参数解释成为真正的ECMAScript语句,插入该函数的位置。
var msg="hello world";
eval("function sayHi(){alert(msg)}"); //很强大的双刃剑,使用时候小心代码注入。
sayHi(); //output "hello world"
2.Math对象
1)属性
E(值e,自然对数的底) LN10(10的自然对数) LN2(2的自然对数)
lOG2E(以2为底E的对数) LOG10E(以10为底E的对数) PI(值π)
SQRT1_2(1/2的平方根) SQRT2(2的平方根)
2)方法
alert(Math.max(3,54,32,16)); //outputs "54" max()方法用来判断一组数中的最大值
alert(Math.min(3,54,32,16)); //outputs "3" min()方法用来判断一组数中的最小值
alert(Math.abs(-1)); //outputs "1" abs()方法用来返回数字的绝对值
alert(Math.ceil(25.5)); //outputs "26" ceil()方法表示向上舍入取整函数
alert(Math.floor(25.5)); //outputs "25" floor()方法表示向下舍入取整函数
alert(Math.round(25.5)); //outputs "26" round()方法是标准的四舍五入取整函数
alert(Math.exp(10)); //outputs "22026.465794806718" exp()把Math.E升到特定的幂
alert(Math.log(Math.exp(10))); /* outputs "10" log()返回特定数字的自然对数,与exp()
本质上功能相反,返回Math.E的多少次指数才等于指定的值。*/
alert(Math.pow(2,10)); //outputs "1024" pow()用于把数字升到指定的幂
alert(Math.sqrt(4)); //outputs "2" sqrt()用于返回指定数字的平方根
Math对象还有一套三角函数方法,如下:
sin(x)返回x的正弦值 cos(x)返回x的余弦值 tan(x) 返回x的正切值
asin(x) 返回x的反正切值 acos(x) 返回x的反余切值 atan(x) 返回x的反正切值
atan2(y,x) 返回y/x的反余弦值
random()方法返回一个0到1之间的随机数,不包括0和1.
var iNum=Math.floor(Math.random()*10+1); //返回1到10之间的随机数
function selectFrom(iFirstValue,iLastValue){
var iChoices=iLastValue-iFirstValue+1;
return Math.floor(Math.random()*iChoices+iFirstValue);
}
var iNum=selectFrom(2,10);//返回2到10之间的随机数
var aColors=["red","green","blue","yellow","black","purple","brown"];
var sColor=aColors[selectFrom(0,aColors.length-1)];//返回Array中的随机项
五、宿主对象
宿主对象(host object)是所有非本地对象,即由ECMAScript实现的宿主环境提供的对
象。所有BOM和DOM都是宿主对象。
六、作用域
1.ECMAScript中只存在公共作用域,可用下划线规约私有成员,如:obj._color
2.ECMAScript没有静态作用域。
3.关键字this总是指向调用该方法的对象,使用它可在任意多个地方重用同一个函数
function showColor(){
alert(this.color); //引用对象属性时,必须使用this关键字。
}
var oCar1=new Object;
oCar1.color="red";
oCar1.showColor=showColor;
var oCar2=new Object;
oCar2.color="blue";
oCar2.showColor=showColor;
oCar1.showColor(); //outputs "red"
oCar2.showColor(); //outputs "blue"
七、定义类或对象
由于工厂方式、构造函数方式、原型方式等各有弊端,所以只介绍它们的混合方式
1.混合的构造函数/原型方式
function Car(sColor,iDoors,iMpg){
this.color=sColor;
this.doors=iDoors;
this.mpg=iMpg;
this.drivers=new Array("Mike","Sue");
}
Car.prototype.showColor=function(){
alert(this.color);
};
var oCar1=new Car("red",4,23);
var oCar2=new Car("blue",4,25);
oCar1.drives.push("Matt");
alert(oCar1.drivers); //outputs "Mike,Sue,Matt"
alert(oCar2.drivers): //outputs "Mike,Sue"
//这种方式是ECMAScript主要采用的方式
2.动态原型方式
function Car(sColor,iDoors,iMpg){
this.color=sColor;
this.doors=iDoors;
this.mpg=iMpg;
this.drivers=new Array("Mike","Sue");
if(typeof Car._initialized=="underfined"){
Car.prototype.showColor=function(){
alert(this.color);
};
Car._initialized=true;
}
}
//这种方式的基本思想与上一个相同,只是更符合传统OOP的类定义
3.实例
1)定义
function StringBuffer(){
this._strings=new Array;
}
StringBuffer.prototype.append=function(str){
this._strings.push(str);
};
StringBuffer.prototype.toString=function(str){
return this._strings.join("");
};
2)使用
var buffer=new StringBuffer();
buffer.append("hello ");
buffer.append("world");
var result=buffer.toString(); //equal "hello world"
3)测试
var d1=new Date();
var str="";
for(var i=0; i<10000; i++){
str+="text";
}
var d2=new Date();
document.write("Concatenation with plus: "+(d2.getTime()-d1.getTime())+"milliseconds");
var oBuffer = new StringBuffer();
d1=new Date();
for(var i=0; i<10000; i++){
oBuffer.append("text");
}
var sResult=buffer.toString();
d2=new Date();
document.write("Concatenation with StringBuffer: "+(d2.getTime()=d1.getTime())+
"milliseconds");
//结果表明StringBuffer类比使用加号节省了100%-200%的时间。
八、修改对象
1.创建新方法
1)可以用prototype属性为任何已有的类定义新方法,就想处理自己的类一样。
Number.prototype.toHexString=function(){
return this.toString(16);
};
var iNum=15;
alert(iNum.toHexString()); //outputs "F"
2)可以添加与已有方法无关的方法。
Array.prototype.indexOf=function(vItem){
for(var i=0; i<this.length; i++){
if(vItem==this[i]){
return i;
}
}
return -1;
}
var aColors=new Array("red","green","yellow");
alert(aColors.indexOf("green")); //outputs "1"
3)通过Object对象的prototype属性,来给ECMAScript中的每个本地对象添加新方法。
Object.prototype.showValue=function(){
alert("警告:"+this.valueOf());
};
var str="hello";
var iNum=25;
str.showValue(); //outputs "警告:hello";
iNum.showValue(); //outputs "警告:25";
2.重定义已有的方法
函数名只是指向函数的指针,因此可以轻易的使它指向其他的函数。
Function.pototype.toString=function(){
return "Function code hidden";
};
function sayHi(){
alert("hi");
}
alert(sayHi.toString()); //outputs "Function code hidden"
输出源代码的toString()原始函数被完全废弃,没有恢复原始函数的方法,所以在覆盖
原始方法之前,存储它的指针比较安全,以便以后的使用。
Function.prototype.originalToString=Function.prototype.toString;
Function.prototype.toString=function(){
if(this.originalToString().length>100){
return "Function too long to dispaly.";
}else{
return this.originalToString();
}
};
3.极晚绑定
技术上不存在极晚绑定,指的是能够在对象实例化后再定义它的方法。
var o=new Object;
Object.prototype.sayHi=function(){
alert("hi");
};
o.sayHi();
不建议使用极晚绑定方法,因为很难对其跟踪和记录。