Javascript在HTML5到来之后,毫无疑问将成为一门重要的编程语言。而随着Javascript 2.0规范的采用,Javascript越来越具有一门强大的编程语言所需的所有特性。在这其中,面向对象编程就是一个重要的方面。
面向对象有四大领域:抽象、封装、继承、多态。下面我们分别来看一看这些概念在Javascript中的实现方式。注意:因为Js设计初衷和应用范围,Js本身并没有提供OO结构,OO的实现更多的是利用Js的动态机制来完成。
首先是抽象,OO中用类来描述客观事物,例如可以将学生整体视为一个类,该类具有姓名、性别、年龄等属性,有入学和毕业两个方法。每个学生都是该类的实例。但是在Javascript中,没有类的语言元素,我们可以用函数来模拟类。
function Student(name, gender, age) {
this.name = name;
this.gender = gender;
this.age = age;
}
Student.prototype.register = function () {…};
Student.prototype.graduate = function() {….};
上述代码定义的学生类,有三个公共属性和两个公共方法,使用方式为:
var st = new Student();
st.name = “Yantao”;
st.register();
其次OO中的重要概念是封装,我们将类的公共接口公开给调用者,但是对内部实现相关的属性和方法,采用私有方法,对外部调用者不可见。这里私有属性和私有方法可以通过如下语法在Javascript中实现:
function Student(_code) {
this.getCode = function () { // 特权函数,可以获取私有属性和方法,同时可供外部调用
return code;
};
this.setCode = function (_code) {
code = _code;
}
var code; // 私有属性
code = _code;
function manage() { // 私有方法}
}
var st = new Student();
st.setCode(“abc”);
如上所述,可以通过私有属性和方法实现信息封装,通过特权函数实现对外接口。注意:公共函数只有获取公用属性和方法。
再次是继承,可以在现有类的基础上创建新类,并对现有类进行扩展。在Javascript中有两种方法可以实现继承,一种是函数方式,一种是原型方式。由于原型方式可以在运行时动态扩展继承基类,因此这里只讨论基于原型的继承。
// 首先定义基类
function Person() {
this.getName = function () {
return name;
}
this.setName = function (_name) {
name = _name;
}
var name = null;
}
Person.prototype.dumpObj = function () {
return "Person.dumpObj";
}
function Student() {
this.getSchool = function () { return school; }
this.setSchool = function (_school) { school = _school;}
var school = null;
}
Student.prototype = new Person;
var p = new Person();
p.setName("Yantao");
alert("Person:" + p.getName());
var s = new Student();
s.setSchool("Huilongguan");
s.setName("Yan an");
alert("student:" + s.getSchool() + ": " + s.getName() + "!");
多态有两种,一种是同一函数名由于参数类型和个数不同而具有不同的行为,这种行为称为Overloading,另一种是相同函数名及参数,子类中的方法覆盖父类中的方法,这种行为称为Overriding。
对于不同参数具有不同行为的情况,可以使用下面代码实现:
Student.prototype.showFunc = function () {
if (1 == arguments.length) {
alert("one argument!");
}
if (2 == arguments.length) {
if (Number == arguments[0].constructor) {
alert("Two: number");
} else if (String == arguments[0].constructor) {
alert("Two: string");
}
}
}
var s = new Student();
s.showFunc("abc");
s.showFunc(20, "ab");
s.showFunc("20", 22);
对于子类覆盖父类方法,可以用如下代码实现:
function Person() {
this.printObj = function () {
return "I am Person!";
}
this.getName = function () {
return name;
}
this.setName = function (_name) {
name = _name;
}
this.modifyName = function () {
return "name=" + name + "!";
}
var name = null;
}
Person.prototype.dumpObj = function () {
return "Person.dumpObj";
}
function Student() {
this.printObj = function () {
var selfStr = "I am Student!" + this.dumpObj() + this.modifyName() + Student.prototype.printObj();
return selfStr;
}
this.getSchool = function () {
return school;
}
this.setSchool = function (_school) {
school = _school;
}
var school = null;
}
Student.prototype = new Person;
Student.prototype.showFunc = function () {
if (1 == arguments.length) {
alert("one argument!");
}
if (2 == arguments.length) {
if (Number == arguments[0].constructor) {
alert("Two: number");
} else if (String == arguments[0].constructor) {
alert("Two: string");
}
}
}
var s = new Student();
//var p = (Person)s;
alert(s.printObj());