意译自KevLinDev上一篇文章,才疏学浅,望指正,英文原文可到这里查看。
    javascript脚本语言是支持面向对象编程(Object Oriented Programming )的,只是javascript实现的方式比较特别,与C++和java中的实现方式不同。在javascript中我们需要借助prototype对象来访问父类的方法,下面将讨论在javascript中实现OOP中最基本的特征关系 --- 继承。
首先,我们从最基本的开始:在javascript中创建对象。创建一个对象包括2步:
1) 创建一个和你想要创建的对象同名的函数(这里可以把这个函数理解为java中的构造函数);
2) 通过调用 new 上面创建的函数名 的方式创建一个对象实例;
// 创建同名函数
function Person(first, last) {
    this.first = first;
    this.last  = last;
}
// 创建实例
var person = new Person("John", "Dough");
注意:构造函数中的this指针指向当前的创建的对象,这与java中的表示是一致的。通过this指针我们可以操作对象的属性。
然后,设置对象的方法:
Person.prototype.toString() {
    return this.first + " " + this.last;
}
alert( person.toString() ); // displays "John Dough"
alert( person ); // alert函数将默认调用toString()函数
在这里我们用到了javascript中的prototype属性。所有的javascript对象都拥有一个prototype属性,javascript就是通过这个属性来实现继承关系的。具体的实现机制是这样的:当你访问一个对象的属性时,编译器将先查找对象的属性看有没有匹配的。如果没有找到,将继续查找这个对象的prototype属性所指的对象,看是否存在匹配的属性。如果还是没有找到,编译器将检查当前对象的prototype是否拥有prototype属性,如果有将继续查找下去。以此类推,直到查找完所有的prototype属性。
从这个过程不难看出,存在着一个类似于继承的访问链,可以把prototype对象指向我们要继承的父类,以此来访问父类的方法。
接下来,我们新建一个类Employee来继承上面的Person类,并且新增一个属性id,在Employee的构造函数中只是初始化属性id,而父类中的属性将由Person的构造函数类设置:
function Person(first, last) {
if ( arguments.length > 0 )
    this.init(first, last);
}
Person.prototype.init = function(first, last) {
    this.first = first;
    this.last  = last;
}
Employee.prototype = new Person();
Employee.prototype.constructor = Employee;
Employee.superclass = Person.prototype;
function Employee(first, last, id) {
    if ( arguments.length > 0 )
        this.init(first, last, id);
}
Employee.prototype.init = function(first, last, id) {    
    // Call superclass method
    Employee.superclass.init.call(this, first, last);
    // init properties
    this.id = id;
}
可以看到,我们把初始化属性的操作提取出来放到了一个init函数中,这样做是为了方便在子类中调用。注意其中的"Employee.superclass = Person.prototype;",这里是一个技巧,方便下面在子类中调用父类的方法。
另一个需要注意的地方是"Employee.superclass.init.call(this, first, last);":对于所有对象中的方法来说,都可以通过两个方法来调用--"call" 和 "apply".
这里使用了call方法,其中第一个参数是将在调用的方法中访问的对象,后面的参数与调用方法的参数一致。
 apply方法的使用与call大致一致,不同在于除了第一个参数外,后面是一个参数数组。
下面附上完整的例子和类图:
继承关系图如下:

代码:



 /**//*****
/**//*****
 *
*
 *    Person constructor
*    Person constructor
 *
*
 *****/
*****/

 function Person(first, last)
function Person(first, last)  {
{
 if ( arguments.length > 0 )
    if ( arguments.length > 0 )
 this.init(first, last);
        this.init(first, last);
 }
}


 /**//*****
/**//*****
 *
*
 *    Person init
*    Person init
 *
*
 *****/
*****/

 Person.prototype.init = function(first, last)
Person.prototype.init = function(first, last)  {
{
 this.first = first;
    this.first = first;
 this.last  = last;
    this.last  = last;
 };
};


 /**//*****
/**//*****
 *
*
 *    Person toString
*    Person toString
 *
*
 *****/
*****/

 Person.prototype.toString = function()
Person.prototype.toString = function()  {
{
 return this.first + "," + this.last;
    return this.first + "," + this.last;
 };
};



 /**//*****
/**//*****
 *
*
 *    Setup Employee inheritance
*    Setup Employee inheritance
 *
*
 *****/
*****/
 Employee.prototype = new Person();
Employee.prototype = new Person();
 Employee.prototype.constructor = Employee;
Employee.prototype.constructor = Employee;
 Employee.superclass = Person.prototype;
Employee.superclass = Person.prototype;


 /**//*****
/**//*****
 *
*
 *    Employee constructor
*    Employee constructor
 *
*
 *****/
*****/

 function Employee(first, last, id)
function Employee(first, last, id)  {
{
 if ( arguments.length > 0 )
    if ( arguments.length > 0 )
 this.init(first, last, id);
        this.init(first, last, id);
 }
}


 /**//*****
/**//*****
 *
*
 *    Employee init
*    Employee init
 *
*
 *****/
*****/

 Employee.prototype.init = function(first, last, id)
Employee.prototype.init = function(first, last, id)  {
{    
 // Call superclass method
    // Call superclass method
 Employee.superclass.init.call(this, first, last);
    Employee.superclass.init.call(this, first, last);

 // init properties
    // init properties
 this.id = id;
    this.id = id;
 }
}


 /**//*****
/**//*****
 *
*
 *    Employee toString
*    Employee toString
 *
*
 *****/
*****/

 Employee.prototype.toString = function()
Employee.prototype.toString = function()  {
{
 var name = Employee.superclass.toString.call(this);
    var name = Employee.superclass.toString.call(this);

 return this.id + ":" + name;
    return this.id + ":" + name;
 };
};



 /**//*****
/**//*****
 *
*
 *    Setup Manager inheritance
*    Setup Manager inheritance
 *
*
 *****/
*****/
 Manager.prototype = new Employee;
Manager.prototype = new Employee;
 Manager.prototype.constructor = Manager;
Manager.prototype.constructor = Manager;
 Manager.superclass = Employee.prototype;
Manager.superclass = Employee.prototype;


 /**//*****
/**//*****
 *
*
 *    Manager constructor
*    Manager constructor
 *
*
 *****/
*****/

 function Manager(first, last, id, department)
function Manager(first, last, id, department)  {
{
 if ( arguments.length > 0 )
    if ( arguments.length > 0 )
 this.init(first, last, id, department);
        this.init(first, last, id, department);
 }
}


 /**//*****
/**//*****
 *
*
 *    Manager init
*    Manager init
 *
*
 *****/
*****/

 Manager.prototype.init = function(first, last, id, department)
Manager.prototype.init = function(first, last, id, department) {
{
 // Call superclass method
    // Call superclass method
 Manager.superclass.init.call(this, first, last, id);
    Manager.superclass.init.call(this, first, last, id);

 // init properties
    // init properties
 this.department = department;
    this.department = department;
 }
}


 /**//*****
/**//*****
 *
*
 *    Manager toString
*    Manager toString
 *
*
 *****/
*****/

 Manager.prototype.toString = function()
Manager.prototype.toString = function()  {
{
 var employee = Manager.superclass.toString.call(this);
    var employee = Manager.superclass.toString.call(this);

 return employee + " manages " + this.department;
    return employee + " manages " + this.department;
 }
}