Javascript对象继承
在Javascript中,一切皆是对象,所谓的类也只是用来模拟其它面向对象语言的class的对象而已,例如:
function MyClass() {}//定义一个类
MyClass.call();//其实这个类本身也是一个对象
在上面的代码中,并没有为MyClass定义call方法,但是却可以调用call方法,其原因就是JavaScript的原生对象在发挥作用。通过function关键字定义一个类,实质上就是实例化一个Function的实例,因为Javascript在Function的原生对象中定义了call方法,所以即使MyClass的定义是空的,但是还是可以调用call方法!由此,我们就可以看到继承的影子!
在原生对象中定义的方法call被继承到了MyClass中,那么只要修改一下原生对象,那么就可以模拟出面向对象的继承机制了。
function MyBaseClass() {
this.Add = function(a, b) {
return a + b;
}
}
function MyClass() {
}
MyClass.prototype = new MyBaseClass();
var obj = new MyClass();
var X = obj.Add(3, 4);
只要把MyClass的原生对象指向基类MyBaseClass的实例对象,那么MyClass就可以继承MyBaseClass中的方法,从而实现了继承机制!
多继承
任何对象的直接原生对象都只有一个,那么如果想实现多继承该怎么办呢?可以采用两种办法:
方法一:链状继承
function MyBaseClassA() {
this.Add = function(a, b) {
return a + b;
}
}
function MyBaseClassB() {
this.Sub = function(a, b) {
return a - b;
}
}
function MyClass() {
}
MyBaseClassB.prototype = new MyBaseClassA();
MyClass.prototype = new MyBaseClassB();
var obj = new MyClass();
var X = obj.Add(3, 4);
var Y = obj.Sub(9, 4);
方法二:拷贝继承
function MyBaseClassA() {
this.Add = function(a, b) {
return a + b;
}
}
function MyBaseClassB() {
this.Sub = function(a, b) {
return a - b;
}
}
function MyClass() {
}
var A = new MyBaseClassA();
for (var method in A) {
MyClass.prototype[method] = A[method];
}
var B = new MyBaseClassB();
for (var method in B) {
MyClass.prototype[method] = B[method];
}
var obj = new MyClass();
var X = obj.Add(3, 4);
var Y = obj.Sub(9, 4);
继承的本质就是属性拷贝,所以只要手动拷贝基类的所有属性,那么就可以实现多继承了,对于拷贝属性的代码可以封装一下,便于调用:
var Extend = function(DeriveClass,BaseClass) {
var o = new BaseClass();
for (var method in o) {
DeriveClass.prototype[method] = o[method];
}
}
Extend(MyClass, MyBaseClassA);
Extend(MyClass, MyBaseClassB);
构造参数:
继承是实现了,但是如果有构造参数有又该怎么处理呢?答案就是在派生类中调用基类构造就可以了:
function MyBaseClass(a, b) {
this.A = a;
this.B = b;
this.Add = function() {
return this.A + this.B;
}
}
function MyClass(a,b,c) {
MyBaseClass.call(this, a, b);//调用基类的构造
}
var Extend = function(DeriveClass, BaseClass) {
var o = new BaseClass();
for (var method in o) {
DeriveClass.prototype[method] = o[method];
}
}
Extend(MyClass, MyBaseClass);
var obj = new MyClass(4,5,8);
var X = obj.Add();
alert(X); //结果:9
call和apply方法是经常用到的两个方法,其作用就是在另一个域内调用方法!
继承机制带来的另一个问题就是同名方法隐藏问题!Javascript对象都是由原型对象生成,原型对象也有其自己的原型对象,这样就构成了一条原型对象链,对象链的顶端指向Object原生对象,末端就是对象本身,如果对象链中存在同名的方法,那么对象链末端的方法访问优先级高于顶端的优先级,因此派生类的方法总是隐藏基类的方法:
var BaseClass=function(){
this.Hello=function(){
return "A";
}
this.say=function(){
return "Saying A";
}
}
var BaseObj = new BaseClass();
var X = BaseObj.Hello();
alert(X); //结果:A
BaseClass.prototype.Hello=function(a,b){
return "B";
}
var Y = BaseObj.Hello();
alert(Y); //结果:A
var MyClass = function(){
this.Hello=function(){
return "C";
}
}
var Extend = function(DeriveClass, BaseClass) {
var o = new BaseClass();
for (var method in o) {
DeriveClass.prototype[method] = o[method];
}
}
Extend(MyClass, BaseClass);
var MyObj = new MyClass();
var Z = MyObj.Hello();
alert(Z); //结果:C
MyClass.prototype.Hello=function(){
return "D";
}
MyClass.prototype.say=function(){
return "Saying D";
}
var K = MyObj.Hello();
alert(K); //结果:C
var L = MyObj.say();
alert(L); //结果:Saying D
方法隐藏的唯一准则就是原型对象链的顺序,方法是否会被隐藏与实现继承的机制相关!
以后再说一说Javascript面向对象的多态特性!
原发布于Javascript对象继承(2009-05-07 22:14),现转于此!