真正的面向对象语言必须支持继承机制,即一个类能够重用(继承)另一个类的方法和属性,在上一篇文章里介绍了 javascript 里的类实现 ,这里介绍下继承的实现。
JavaScript里的继承机制并不是明确规定的,而是通过模仿实现的。
一:对象冒充(object masquerading)
对象冒充是如何在函数环境中使用this关键字后发展起来的,其原理如下:构造函数使用this关键字给所有的属性和方法赋值(采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可以使用ClassA的构造函数成为ClassB的方法,然后调用它。ClassB就会收到ClassA的构造函数中定义的属性和方法。
call()方法是与经典的对象冒充方法最相似的方法,它的第一个参数用作this的对象,其它参数都直接传递给函数自身,如:
三:apply()方法
apply()方法有二个参数,用作this的对象和要传递给函数的参数数组,列如:
prototype对象是个模板,要实例化的对象都以这个模板为基础,prototype对象的任何属性和方法都被传递给那个类的所有实例,原型链用这种功能实现继承机制:
这种方式使用构造函数定义类,并未使用任何原型。重写前面的例子,代码如下:
JavaScript里的继承机制并不是明确规定的,而是通过模仿实现的。
一:对象冒充(object masquerading)
对象冒充是如何在函数环境中使用this关键字后发展起来的,其原理如下:构造函数使用this关键字给所有的属性和方法赋值(采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可以使用ClassA的构造函数成为ClassB的方法,然后调用它。ClassB就会收到ClassA的构造函数中定义的属性和方法。
function ClassA(sColor)
{
this.color = sColor;
this.sayColor = function()
{
alert(this.color);
};
}
function ClassB(sColor)
{
this.newMethord= ClassA;
this.newMethod(sColor);
delete this.newMethod;
}
上面的代码中ClassA赋予了方法newMethod(函数只是指向它的指针)。然后调用了该方法,传递给它的是ClassB的构造函数的参数sColor。最后的代码删除了对ClassA的引用,这样以后就不能再调用它了,所有的新属性和新方法都必须在删除了新方法的代码行后定义,否在会覆盖超类的相关属性和方法:{
this.color = sColor;
this.sayColor = function()
{
alert(this.color);
};
}
function ClassB(sColor)
{
this.newMethord= ClassA;
this.newMethod(sColor);
delete this.newMethod;
}
function ClassB(sColor,sName)
{
this.newMethor = ClassA;
this.newMethor(sColor);
delete this.newMethor;
this.name = sName;
this.sayName = function()
{
alert(this.name);
};
}
二:call()方法{
this.newMethor = ClassA;
this.newMethor(sColor);
delete this.newMethor;
this.name = sName;
this.sayName = function()
{
alert(this.name);
};
}
call()方法是与经典的对象冒充方法最相似的方法,它的第一个参数用作this的对象,其它参数都直接传递给函数自身,如:
function sayColor(sPrefix,sSuffix)
{
alert(sPrefix + this.color + sSuffix);
}
var obj = new object();
obj.color = "red";
sayColor.call(obj,"The color is ",", a very nice color indeed.");
//outputs "The color is red, a very nice color indeed."
在上面的例子里,函数sayColor()在对象外定义,即使它不属于任何对象,也可以引用关键字this,对象obj的color属性等于"red",调用call()方法时对一个参数是obj,说明应赋予sayColor()函数中的this关键字是obj,要与继承机制的对象冒充方法一起使用该方法,只需将前三行的赋值,调用和删除代码替换:{
alert(sPrefix + this.color + sSuffix);
}
var obj = new object();
obj.color = "red";
sayColor.call(obj,"The color is ",", a very nice color indeed.");
//outputs "The color is red, a very nice color indeed."
function ClassB(sColor,sName)
{
// this.newMethor = ClassA;
// this.newMethor(sColor);
// delete this.newMethor;
ClassA.call(this,sColor);
this.name = sName;
this.sayName = function()
{
alert(this.name);
};
}
{
// this.newMethor = ClassA;
// this.newMethor(sColor);
// delete this.newMethor;
ClassA.call(this,sColor);
this.name = sName;
this.sayName = function()
{
alert(this.name);
};
}
三:apply()方法
apply()方法有二个参数,用作this的对象和要传递给函数的参数数组,列如:
function sayColor(sPrefix,sSuffix)
{
alert(sPrefix + this.color + sSuffix);
}
var obj = new object();
obj.color = "red";
sayColor.apply(obj,new Array("The color is ",", a very nice color indeed."));
//outputs "The color is red, a very nice color indeed."
四:原型链{
alert(sPrefix + this.color + sSuffix);
}
var obj = new object();
obj.color = "red";
sayColor.apply(obj,new Array("The color is ",", a very nice color indeed."));
//outputs "The color is red, a very nice color indeed."
prototype对象是个模板,要实例化的对象都以这个模板为基础,prototype对象的任何属性和方法都被传递给那个类的所有实例,原型链用这种功能实现继承机制:
function ClassA()
{
}
ClassA.prototype.color = "red";
ClassA.prototype.sayColor = function()
{
alert(this.color);
};
function ClassB()
{
}
ClassB.prototype = new ClassA();
ClassB.prototype = new ClassA(); 这句把ClassB的prototype属性设置为ClassA的实例,与对象冒充相似,子类的所有属性和方法都必须出现在prototype属性被赋值后,因为在它之前所有的方法都会被删除,因为prototype属性被替换成了新的对象,添加了新的原始对象将被销毁,所以,为ClassB类添加name属性和sayName()方法的代码如下:{
}
ClassA.prototype.color = "red";
ClassA.prototype.sayColor = function()
{
alert(this.color);
};
function ClassB()
{
}
ClassB.prototype = new ClassA();
function ClassB()
{
}
ClassB.prototype = new ClassA();
ClassB.prototype.name = "";
ClassB.prototype.sayName = function()
{
alert(this.name);
};
五:混合方式{
}
ClassB.prototype = new ClassA();
ClassB.prototype.name = "";
ClassB.prototype.sayName = function()
{
alert(this.name);
};
这种方式使用构造函数定义类,并未使用任何原型。重写前面的例子,代码如下:
function ClassA(sColor)
{
this.color = sColor;
}
ClassA.prototype.sayColor = function()
{
alert(this.color);
};
function ClassB(sColor,sName)
{
ClassA.call(this,sColor);
this.name = sName;
}
ClassB.prototype = new ClassA();
ClassB.prototype.sayName = function()
{
alert(this.name);
}
{
this.color = sColor;
}
ClassA.prototype.sayColor = function()
{
alert(this.color);
};
function ClassB(sColor,sName)
{
ClassA.call(this,sColor);
this.name = sName;
}
ClassB.prototype = new ClassA();
ClassB.prototype.sayName = function()
{
alert(this.name);
}