面向对象是一种新兴的程序设计方法,一种新的程序设计规范,其基本思想是使用对象、类、继承、封装、消息等基本概念来进行程序设计。从现实世界中客观存在的事物(即对象)出发来构造软件系统,并且在系统构造中尽可能运用人类的自然思维方式。
面向对象最重要的两个概念就是对象和类。
对象是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位。一个对象由一组属性和对这组属性进行操作的一组函数组成。
类是具有相同属性和函数的一组对象的集合,它为属于该类的所有对象提供了统一的抽象描述,其内部包括属性和函数两个主要部分。但是需要注意的是,JavaScript语言中并没有提供类的定义能力,只能直接创建对象。
在JavaScript语言中虽然不能定义类,但可以直接创建对象,面向对象的效果是一样的。JavaScript语言中创建对象代码的写法与其他常见语言(如Java、C#和C++等)完全不同,有多种函数可以创建JavaScript中的对象。下面分别介绍一下。
1.使用字面量创建对象
JavaScript中的对象与数值、字符串等类似,都属于基本数据类型,它们可以使用字面量来表示。对象字面量类似于JSON
对象,采用对象字面量表示的JavaScript对象是一个无序的“名称,值”对集合,一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号),“名称,值”对之间使用“,”(逗号)分隔,语法如图2-11所示。
图2-11 JavaScript对象字面量表示语法结构图
字面量的每一个“名称,值”对就是对象的一个属性。
实例代码如下:
var Person={ ① name:"Tony", ② age :18, ③ description :function() { ④ var rs=this.name + "的年龄是:" +this.age; ⑤ return rs; } } var p=Person; ⑥ console.log(p.description()); ⑦
上述代码创建了Person对象,其中第①行代码是声明对象名为Person,第②行代码是定义Person对象的name属性,第③行代码是定义Person对象的age属性,它们都采用“名称,值”对方式。第④行代码很特殊,它是定义对象的description函数,也是采用“名称/值”对结构,但是“值”部分是一个函数。第⑤行代码是访问对象的name和age属性,需要使用this关键字,this关键字指代当前对象。第⑥行代码var p=Person是将Person对象赋值给p变量,这时p和Person是同一个东西。第⑦行代码调用Person对象description()函数。
2.使用Object.create()函数创建对象
可以使用Object.create()函数,它的优势在于能够在原来对象基础上复制出一个新的对象。
实例代码如下:
var Person={ ① name:"Tony", age:18, description:function () { var rs=this.name + "的年龄是:" + this.age; return rs; } } var p=Person; console.log(p.description()); var p1=Object.create({ ② name:"Tom", age:28, description:function () { var rs=this.name + "的年龄是:" + this.age; return rs; } }); console.log(p1.description()); var p2=Object.create(Person); ③ p2.age=29; ④ console.log(p2.description()); console.log(Person.description()); ⑤
运行结果如下:
Tony的年龄是:18 Tom的年龄是:28 Tony的年龄是:29 Tony的年龄是:18
上述代码第①行创建对象Person,第②行和第③行代码都是通过Object.create()函数创建对象。但是第②行Object.create()函数的参数还是采用对象字面量标识。第③行的Object.create()函数的参数Person对象相当于赋值了Person对象,而且是“深层复制”,但在第④行修改p2对象的age属性后,不会对Person对象产生任何影响,所以在第⑤行代码打印Person对象的内容时仍然是“Tony的年龄是:18”。
3.使用函数对象
还可以通过构造函数创建对象。实例代码如下:
function Student(name, age) { ① this.name=name; ② this.age=age; ③ this.description=function () { ④ var rs=this.name + "的年龄是:" + this.age; ⑤ return rs; } } var p3=new Student('Tony', 28); ⑥ var p4=new Student('Tom', 38); ⑦ console.log(p3.description()); console.log(p4.description());
上述代码第①行是声明构造函数,构造函数可以初始化对象属性,其中name和age是构造函数的参数。第②行代码this.name=name是通过name参数初始化name属性,第③行代码this.age=age是通过age参数初始化age属性。第④行代码很特殊,它是定义对象的description函数,第⑤行代码是访问对象的name和age属性,需要使用this关键字,this关键字指代当前对象。第⑥行和第⑦行代码是创建Student对象p3和p4,p3和p4是两个不同的对象。
在JavaScript中有一些常用的内置对象,它们包括Object、Array、Boolean、Number、String、Math、Date、RegExp和Error。
下面分别介绍Object、String、Math和Date等类的使用。
1.Object对象
Object对象是所有JavaScript对象的根,每一个对象都继承于Object对象。实例代码如下:
var o=new Object(); ① console.log(o.toString()); ② console.log(o.constructor); ③ console.log(o.valueOf()); ④
运行结果如下:
[object Object] [Function:Object] {}
上述代码第①行是创建Object对象,第②行代码是调用Object对象的toString()函数,该函数返回描述对象的字符串。第③行代码是调用Object对象的constructor属性,可以返回对象的构造函数。第④行代码是调用Object对象的valueOf()函数,可以返回对象的对应值。
2.String对象
String是字符串对象,String对象有很多常用函数。实例代码如下:
var s=new String("Tony Guan"); ① console.log(s.length); //9 ② console.log(s.toUpperCase()); //TONY GUAN ③ console.log(s.toLowerCase()); //tony guan ④ console.log(s.charAt(0)); //T ⑤ console.log(s.indexOf('n')); //2 ⑥ console.log(s.lastIndexOf('n')); //8 ⑦ console.log(s.substring(5, 9)); //Guan ⑧ console.log(s.split(" ")); //[ 'Tony', 'Guan' ] ⑨
上述代码第①行是创建String对象,第②行代码调用String对象的length属性,属性length是获得字符串的长度。第③行代码调用String对象的toUpperCase()函数,它将字符串中的字符转换为大写。第④行代码调用String对象的toLowerCase()函数,它将字符串中的字符转换为小写。第⑤行代码调用String对象的charAt(index)函数,获得字符串index索引位置的字符。第⑥行代码调用String对象的indexOf('n')函数,从前面查找字符串中字符串n所在的位置。第⑦行代码调用String对象的lastIndexOf('n')函数,从后面查找字符串中字符串n所在的位置。第⑧行代码调用String对象的substring(5, 9)函数,截取子字符串5为开始位置,9为结束位置。第⑨行代码调用String对象的split(" ")函数,指定字符分割字符串,返回值是数组类型。
3.Math对象
Math对象是与数学计算有关系的对象。实例代码如下:
console.log(Math.PI); ① console.log(Math.SQRT2); ② console.log(Math.random()); ③ console.log(Math.min(1,2,3)); ④ console.log(Math.max(1,2,3)); ⑤ console.log(Math.pow(2, 3)); ⑥ console.log(Math.sqrt(9)); ⑦
上述代码第①行Math.PI是获得圆周率常量,第②行代码Math.SQRT2是2的平方根,第③行代码Math.random()是获得0~1之间随机数,第④行代码是获得集合中的最小值,第⑤行代码是获得集合中的最大值。第⑥行代码Math.pow(2, 3)是计算2的3次幂。第⑦行代码Math.sqrt(9)是计算9的平方根。
4.Date对象
Date是日期对象。实例代码如下:
var d=new Date(); ① console.log(d.toString());② var d=new Date('2009 11 12'); ③ console.log(d.toString()); var d=new Date('1 2 2012'); ④ console.log(d.toString()); console.log(d.getYear()); //112 ⑤ console.log(d.getMonth()); //0 ⑥ console.log(d.getDay()); //1 ⑦
运行结果如下:
Sat Aug 30 2014 15:06:44 GMT+0800 (中国标准时间) Thu Nov 12 2009 00:00:00 GMT+0800 (中国标准时间) Mon Jan 02 2012 00:00:00 GMT+0800 (中国标准时间) 112 0 1
上述代码第①、③和④行创建Date对象,它们提供了不同的构造函数,其中第①行构造函数是空的,它能够获得当前系统时间;第③行代码的构造函数是通过年、月、日创建对象;第④行代码的构造函数是通过月、日、年格式创建对象。第②行代码通过toString()函数输出对象的描述信息,这些信息是对象日期相关信息。第⑤行代码通过getYear()函数获得日期对象的“年”信息,这个“年”是需要+1900才是习惯的表示方式。第⑥行代码通过getMonth()函数获得日期对象的“月”信息,这个“月”需要+1才是习惯的表示方式。第⑦行代码通过getDay()函数获得日期对象的“星期”信息,如果是星期日,getDay()函数返回0;如果是星期一,getDay()函数返回1。依此类推,星期六返回6。
每一个JavaScript对象都是从一个原型继承而来的,可以通过它的prototype属性获得该原型对象。JavaScript对象继承机制建立在原型模型基础之上。
下面通过矢量对象介绍一下原型的使用,我们知道,在物理学中矢量是有方向和大小的,因此需要两个属性分别表示大小和方向。矢量Vector对象代码如下:
function Vector(v1, v2) { ① this.vec1=v1; ② this.vec2=v2; ③ this.add=function (vector) { ④ this.vec1=this.vec1 + vector.vec1; ⑤ this.vec2=this.vec2 + vector.vec2; ⑥ } this.toString=function () {⑦ console.log("vec1=" + this.vec1 + ", vec2=" + this.vec2); } } var vecA=new Vector(10.5, 4.7); var vecB=new Vector(32.2, 47); //vecA=vecA + vecB 赋值给vecA vecA.add(vecB); vecA.toString();
运行结果如下:
vec1=42.7, vec2=51.7
上述代码第①行声明Vector矢量对象,代码第②行和第③行定义的vec1和vec2属性分别代表矢量的大小和方向属性。第④行代码定义两个矢量相加函数,第⑤行代码是两个矢量的vec1属性相加,第⑥行代码是两个矢量的vec2属性相加。第⑦行代码是定义打印矢量内容函数。
随着需要的变化,还需要矢量相减函数,可以使用原型扩展矢量相减功能。实例代码如下:
function Vector(v1, v2) { this.vec1=v1; this.vec2=v2; this.add=function (vector) { this.vec1=this.vec1 + vector.vec1; this.vec2=this.vec2 + vector.vec2; } this.toString=function () { console.log("vec1=" + this.vec1 + ", vec2=" + this.vec2); } } Vector.prototype.sub= function (vector) { ① this.vec1=this.vec1 - vector.vec1;② this.vec2=this.vec2 - vector.vec2;③ } var vecA=new Vector(10.5, 4.7); var vecB=new Vector(32.2, 47); vecA.sub(vecB); vecA.toString();
运行结果如下:
vec1=-21.700000000000003, vec2=-42.3
上述代码第①行是增加sub(矢量相减)函数,Vector.prototype是矢量对象的原型属性。第②行代码是两个矢量的vec1属性相减,第③行代码是两个矢量的vec2属性相减。
不仅可以使用原型扩展对象函数,还可以扩展对象的属性。