面向对象的Javascript - 通过原型(Prototype)实现继承

Prototype的使用方式


Prototype(原型)是Javascript中实现对象继承的基础方式,使用方式为 [function].prototype = [object1]

[function]可认为相当于type/class,这样可以使该类型的所有对象继承[object1]中所有Public的属性和方法。在这里public的意思是使用了this.xxx。

先看以下例子

View Code
function Person() {
this.fullName = "Unknown";
this.sex = "Male";
this.speek = function(){
console.log(this.fullName + " is speeking");
}
}
function Staff() {
this.id = 1001;
this.title = "Developer";
}
Staff.prototype = new Person();

var s1 = new Staff();
console.log(s1.sex); //==> Male
s1.speek(); //==> Unknown is speeking

 * 注: console.log的结果可以在浏览器开发人员工具/Firebug中的Console(控制台)中查看

通过指定Staff.prototype = new Person(), Staff类型的对象s1获得了Person的属性和方法。

Prototype的原理及实现方式


绝大多数的javascript对象都有原型对象,这些原型对象的应用形成一条“原型链”,链的尽头是Object.prototype。当调用对象的某属性或方法时,js引擎现在当前对象中查找,找不到的话就会查找其原型对象,如此上溯直到到达Object.prototype。我们所熟知的toString,valueOf等方法正是定义在Object.prototype中,因此所有js对象都通过继承获得这些方法。

在Chrome和Firefox里,原型对象可以通过对象的属性"__proto__"访问,该属性实际上指向对应类型的”prototype”属性,即[object].__proto__ == [function].prototype。

在未指定继承状态下,每一个对象都具有一个默认的__proto__对象,而该__proto__的上一级原型对象为Object.prototype.

 

当指定Staff继承自Person之后,__proto__属性会指向personObj,原型链也会随之变化

 

支持带参数的构造函数


在第一点的代码例子中,考虑构造函数带参数的情况。

View Code
function Person(fullName, sex) {
this.fullName = fullName || "Unknown";
this.sex = sex || "Male";
this.speek = function(){
console.log(this.fullName + " is speeking");
}
}
function Staff(id, title, fullName, sex) {
this.id = id || 1001;
this.title = title || "Developer";
}
Staff.prototype = new Person();
var s1 = new Staff(99, "Manager","Eva", "Female");
console.log(s1.fullName); //==> Unknown

 发现通过new Staff(…)无法对fullName和sex赋值,因为在指定继承关系的时候并没有把参数传进Person的构造函数中。要解决此问题需要在Staff中将参数传进Person,答案就是改变__prop__属性。

View Code
function Person(fullName, sex) {
this.fullName = fullName || "Unknown";
this.sex = sex || "Male";
this.speek = function(){
console.log(this.fullName + " is speeking");
}
}
function Staff(id, title, fullName, sex) {
if(this.__proto__){ //For Firefox, Chrome
          this.__proto__ = new Person(fullName, sex);
    }else{                //For IE
          Person.call(this,fullName, sex);
    }
this.id = id || 1001;
this.title = title || "Developer";
}
Staff.prototype = new Person();
var s1 = new Staff(99, "Manager","Eva", "Female");
console.log(s1.fullName); //==> Eva

IE不支持__prop__属性,可以使用call/apply方法,该方法将带参数地调用Person()方法,并且将this作为Person()方法的当前对象。

这种做法所有浏览器都支持,所以通常直接使用call/apply即可,上述例子只是为说明__proto__属性的作用。

posted on 2011-12-16 18:45  Teddy Li  阅读(1193)  评论(4编辑  收藏  举报