Javascript类的原型对象和继承

基本对象分析

JavaScript中所有的东西都是对象,包括函数、字符、数字等等等。但是JavaScript没有Class这个概念。

JavaScript使用Function来模拟类,任何一个function都有一个对应的prototype对象来存储和扩展这个function的定义,也就是说原型对象是关联于函数的

我们计划使用new关键字来调用并生成新对象的函数,我们称为“构造函数”

一个基本的函数分析

function Car(){
	color = 'red';
};

echo(Car);
echo(Car.constructor);
echo(Car.prototype);
echo(Car.prototype.constructor);

输出结果

function Car() { color = "red"; }
function Function() { [native code] }
[object Object]
function Car() { color = "red"; }
  1. Car本身是一个函数
  2. 它的constructor是原生对象(Native Function)
  3. 在函数Car定义解析的同时,会系统生成一个对象 Car.prototype,它将会是所有由Car生成(new)的实例对象的原型对象,注意它是对象,这不同于常见的Class概念。默认的原型对象没有任何属性
  4. Car的原型对象的Constructor就是Car自己,这也说明了原型对象是在函数定义的同时产生的。

原型对象

函数的原型对象是在脚本引擎解析每个函数代码时自动生成的,而不是执行时才生成

//function Car 是显式定义的,Car.prototype已经在代码解析时自动生成了,此时可以访问
echo(Car.prototype); 
function Car(){};

//function Plan 是赋值定义的,Plan.prototype没有自动生成了,此时不能访问
echo(Plan.prototype); 
Plan = function(){};
//现在才可以访问
echo(Plan.prototype); 

原型对象实际的工作方式是一种链式查找,脚本运行时,脚本引擎首先在当前实例对象中查找指定的属性,如果有就直接使用,如果没有就到原型对象中找,如果原型对象也没有,就到原型对象的原型对象中查找,这是一个递归的查找链。所有的JavaScript对象的查找链最终都会归结到原生函数Object的原型对象中去。

function Car(){
	this.color = 'red';
};

Car.prototype.color = 'blue';
Car.prototype.doors = 4;
Object.prototype.wheels = 4;

aCar = new Car;
echo(aCar.color);
echo(aCar.doors);
echo(aCar.wheels);

 

输出结果:

red  //注意:这里构造函数中定义的属性color覆盖了原型中的color定义
4 //从原型中查找到了doors
4 //从根原型中查找到了wheels

 

实例对象的原型对象关系链是有脚本引擎内部维护的,我们不能操作和修改它,但是可以通过定义和修改构造函数的prototype属性来影响的以后生成(new)的实例对象的原型对象,而JavaScript的继承关系正是通过这一方式来模拟的。

 

类的继承

JavaScript所有原生函数(Function,Array..)的Prototype对象指针是只读的,不能修改。你可以改变原型的内容,但不能改变原型对象本身。

而非原生函数的的原型对象是可以修改,如果把一个函数(A)的原型定义(prototype)指向另一个函数函数(B)的实例,这样可以就模拟出A继承B的效果

其实际效果是:把B的原型对象插入到了A的实例对象的原型链中去:

new A > A.prototype > B.prototype > …. > Object.prototype

//这样的代码是不能执行的
Array.prototype = new String('');

function Car(){}
function RaceCar(){}
//RaceCar 现在继承了 Car 的定义
RaceCar.prototype = new Car; 

考虑到修改函数原型对象时可能会造成修改前的原型定义丢失,所有应该仅可能早的指定原型对象。

同时你也许需要修改新原型对象的constructor,使其指向当前构造函数,典型的继承关系处理代码如下:

function Car(){
	Car.prototype.color = 'blue';
	this.doors = 4;
}

function RaceCar(){
	RaceCar.prototype.color = 'red';
	this.doors = 2;
}
RaceCar.prototype = new Car; //RaceCar 现在继承了 Car 的定义
RaceCar.prototype.constructor = RaceCar;  //修改constructor

aCar = new RaceCar();

Car.prototype.wheels = 4;

echo(aCar.color);
echo(aCar.wheels);

输出结果为:

red
4

11

建模结构图

我们使用一段代码及其对应的建模结构图来进一步说明JavaScript的继承处理方式:

代码:

function A(){

}

B.prototype = new A; 
B.prototype.constructor = B;

function B(){

}

结构图:

 

prototype

 

参考:http://mckoss.com/jscript/object.htm

发表评论