//---------------《-》、《继承的基本写法》-----------------------
/* 《-》、《继承的基本原理》
* 对象冒充
* this 指向的所属的对象。这个原理是把 ClassA 作为常规函数来建立继承机制,而不是作为构造函数。如下使用构造函数 ClassB 可以实现继承机制:
*/
function ClassA(sColor) {
this.color = sColor;
this.sayColor = function () {
alert(this.color);
};
}
function ClassB(sColor) {
this.newMethod = ClassA;
this.newMethod(sColor);//即ClassB对象 调用ClassA对象,这时ClassA里面的this 指向ClassB 对象。 从而达到继承的目的。
delete this.newMethod;
}
/*
* 在这段代码中,为 ClassA 赋予了方法 newMethod(请记住,函数名只是指向它的指针)。然后调用该方法,传递给它的是 ClassB 构造函数的参数 sColor。
* 最后一行代码删除了对 ClassA 的引用,这样以后就不能再调用它。
*/
function ClassZ() {
this.newMethod = ClassX;
this.newMethod();
delete this.newMethod;
this.newMethod = ClassY;
this.newMethod();
delete this.newMethod;
}
//所以可以多重基础
//---------------《二》、call() 方法-----------------------
/*
* call() 方法是与经典的对象冒充方法最相似的方法。它的第一个参数用作 this 的对象。其他参数都直接传递给函数自身。例如:
*/
function ClassB(sColor, sName) {
//this.newMethod = ClassA;
//this.newMethod(color);
//delete this.newMethod;
ClassA.call(this, sColor);//我们需要让 ClassA 中的关键字 this 等于新创建的 ClassB 对象,因此 this 是第一个参数。第二个参数 sColor 对两个类来说都是唯一的参数(可以多个)。
this.name = sName;
this.sayName = function () {
alert(this.name);
};
}
//缺点 因为是对象冒充,所以只能继承 父类中用 this 定义的属性和方法,二对于prototype 定义的不能继承
function ClassA(sColor) {
this.color = sColor;
if (typeof ClassA._initialized == "undefined") {
ClassA.prototype.sayColor = function () {
alert(this.color);
};
ClassA._initialized = true;
}
}
function ClassB(sColor, sName) {
ClassA.call(this, sColor);// 只能继承 ClassA 里面用this定义的属性和方法
this.name = sName;
this.sayName = function () {
alert(this.name);
};
}
var testObj=new ClassB('blue','testObk');
testObj.sayColor();//error:testObj.sayColor is not a function
testObj.sayName();
//---------------《二》、apply() 方法-----------------------
/*这个例子与前面的例子相同,只是现在调用的是 apply() 方法。调用 apply() 方法时,第一个参数仍是 obj,说明应该赋予 sayColor() 函数中的 this 关键字值是 obj。
* 第二个参数是由两个字符串构成的数组,与 sayColor() 函数中的参数 sPrefix 和 sSuffix 匹配,
* 最后生成的消息仍是 "The color is blue, a very nice color indeed.",将被显示出来。
*/
function ClassB(sColor, sName) {
//this.newMethod = ClassA;
//this.newMethod(color);
//delete this.newMethod;
ClassA.apply(this, new Array(sColor));
this.name = sName;
this.sayName = function () {
alert(this.name);
};
}
//同样的,第一个参数仍是 this,第二个参数是只有一个值 color 的数组。可以把 ClassB 的整个 arguments 对象作为第二个参数传递给 apply() 方法:
function ClassB(sColor, sName) {
//this.newMethod = ClassA;
//this.newMethod(color);
//delete this.newMethod;
ClassA.apply(this, arguments);
this.name = sName;
this.sayName = function () {
alert(this.name);
};
}
//缺点 因为是对象冒充,所以只能继承 父类中用 this 定义的属性和方法,二对于prototype 定义的不能继承
//---------------《三》、原型链(prototype chaining)-----------------------
/* 在上一章学过,prototype 对象是个模板,要实例化的对象都以这个模板为基础。
* 总而言之,prototype 对象的任何属性和方法都被传递给那个类的所有实例。原型链利用这种功能来实现继承机制。
*/
function ClassA() {}
ClassA.prototype.color = "blue";
ClassA.prototype.sayColor = function () {
alert(this.color);
};
function ClassB() {}
ClassB.prototype = new ClassA();//原型方式的神奇之处在这里,把 ClassB 的 prototype 属性设置成 ClassA 的实例。
//注意:调用 ClassA 的构造函数,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。
//此外,在原型链中,instanceof 运算符的运行方式也很独特。对 ClassB 的所有实例,instanceof 为 ClassA 和 ClassB 都返回 true。例如:
var objB = new ClassB();
alert(objB instanceof ClassA); //输出 "true"
alert(objB instanceof ClassB); //输出 "true"
//原型链的弊端是不支持多重继承。记住,原型链会用另一类型的对象重写类的 prototype 属性。
// 不能把 子类的参数传个 父类 传参数
//---------------《四》、混合方式-----------------------------
/* 这种继承方式使用构造函数定义类,并非使用任何原型。对象冒充的主要问题是必须使用构造函数方式,这不是最好的选择。
不过如果使用原型链,就无法使用带参数的构造函数了。开发者如何选择呢?答案很简单,两者都用。
*/
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 方法前。应为该行是从写ClassB 的 原型模板,所以在之前定义的原型方法将丢失
ClassB.prototype.sayName = function () {
alert(this.name);
};
/*=============================================================
* 关于js 类的创建和继承 终结 |
* 《最佳实现方式》 |
* ---根据http://www.w3school.com.cn 总结而来 |
//=============================================================*/
/* 类的定义使用《原型方式》(不浪费内存)
* 继承使用 《混合方式》(冒充和原型结合)
* 代码如下:
*/
var ShowForm=function(options,formID){
this.opt = {
renderto:'body',
formBasePriceBlock:'#basePrice',
forQue_TotalCostBlock:'#preferredOption',
formTotalCostBlock:'#totalCost'
};
$.extend(this.opt, options);//使用了Jquery ,扩展opt对象(有则重写,没有则加入,请参考Jquery $.extend() )
this.init(formID);
this.itemCount=0;
this.fb_itemIDName='fb-item-';
};
ShowForm.prototype.methodA(){};
ShowForm.prototype.methodB(variableA){};
ShowForm.prototype.methodC(variableA,variableB,variableC){};
//使用
var testObjt=new ShowForm({ //创建对象,并传一个对象到构造函数
renderto:'#myDocID',
});
//继承
function ClassB(sColor, sName) {
ShowForm.call(this, {});
this.name = sName;
}
ClassB.prototype = new ClassA();
ClassB.prototype.methodInClassB=function(){};
//结合完整实例:
var ShowForm=function(options){
this.opt = {
renderto:'body',
formBasePriceBlock:'#basePrice',
forQue_TotalCostBlock:'#preferredOption',
formTotalCostBlock:'#totalCost',
color:'red',
name:'showForm'
};
$.extend(this.opt, options);//使用了Jquery ,扩展opt对象(有则重写,没有则加入,请参考Jquery $.extend() )
//this.init(formID);
this.iItemCount=0;
this.sFb_itemIDName='fb-item-';
};
ShowForm.prototype.methodA=function(){
alert('color:'+this.opt.color+',name:'+this.opt.name);
};
ShowForm.prototype.methodB=function(variableA){
return this.bname;//访问子类的属性,是可以的
};
ShowForm.prototype.methodC=function(){
return this.opt.formBasePriceBlock;
};
ShowForm.prototype.methodD=function(variableA,variableB,variableC){};
function ClassB(sColor, sName) {
this.bname = 'Bname';
ShowForm.call(this,{
color:sColor,
name:sName
}//传一个对象给父类
);
//this.name = sName;
}
ClassB.prototype = new ShowForm();
ClassB.prototype.methodInClassA=function(){
alert("methodInClassA access ShowForm's attribute,renderto:"+this.opt.renderto);
};
ClassB.prototype.methodInClassB=function(){
alert("methodInClassB access ShowForm's methodB:"+this.methodB());
};
ClassB.prototype.methodInClassC=function(){
alert("methodInClassC access ShowForm's methodC:"+this.methodC());
};
var testObj=new ClassB('blue','yellow');
testObj.methodA(); //输出 color:blue,name:yellow
testObj.methodInClassA(); //输出 methodInClassA access ShowForm's attribute,renderto:body
testObj.methodInClassB(); //输出 methodInClassB access ShowForm's methodB:Bname
testObj.methodInClassC(); //输出 methodInClassC access ShowForm's methodC:#basePrice