JavaScript中类的继承机制
JavaScript的面向对象编程相比其他语言确实比较麻烦。之前看到,单是类的定义就有很多种方式,而类的继承也有很多方式。这是因为JavaScript中的继承机制并不是明确规定的,而是通过模仿实现的。现把书上提到的方法总结如下代码.其中需要注意的重点已经作为注释标明。其中第五种——混合方式对应定义类的方法中的混合构造函数/原型方式,所以也是最佳的方式。
要用ECMAScript实现继承机制,首先要从基类入手。所有开发者定义的类都可以做外基类。出于安全考虑,本地类和宿主类不能所为基类,这样可以避免访问编译过的浏览器级的代码。
//此文件说明JavaScript中几种类的继承机制 //函数 extendsmethodn(n=1:5) 仅为分割代码和测试方便,实际继承方式仅为函数内的代码 //extendsmethod5(); //1、对象冒充(call方法和apply方法其实也可看做对象冒充) function extendsmethod1(){ function ClassA(sColor){ this.color = sColor; this.sayColor = function(){ alert(this.color); }; } function ClassB(sColor, sName){ this.newMethod = ClassA; this.newMethod(sColor); //此处调用传递给ClassB的ClassA方法 delete this.newMethod; //新的属性都要在删除父类对象后再定义 this.name = sName; this.sayName = function(){ alert(this.name); }; } //测试 var objA = new ClassA("red"); var objB = new ClassB("blue", "Nicholas"); objA.sayColor(); //objA.sayName(); 这句会导致错误,ClassA类没有sayName方法。 objB.sayColor(); objB.sayName(); //继承多个类,假设已存在 ClassX ClassY两个类 /* function ClassZ(){ this.newMethod = ClassX; this.newMethod(); delete this.newMethod; this.newMethod = ClassY; this.newMethod(); delete this newMethod; } */ } //2、call()方法 function extendsmethod2(){ function sayColor(sPrefix, sSuffix){ document.write(sPrefix + this.color +sSuffix); } var obj = new Object(); obj.color = "red"; sayColor.call(obj,"The color is ", ", a very nice color indeed.");//call第一个参数为传递给前面的sayColor方法中 this 的对象,后面为传递给sayColor的其他参数 //输出结果:The color is red, a very nice color indeed. 此例说明 call 方法的用法 //使用call方法继承 function ClassB(sColor, sName){ //this.newMethod = ClassA; //this.newMethod(sColor); //delete this.newMethod; ClassA.call(this, sColor); //此方法代替上面3行的效果,ClassA定义同对象冒充方法 this.name = sName; this.sayName = function(){ alert(this.name); }; } } //3、apply()方法 function extendsmethod3(){ function sayColor(sPrefix, sSuffix){ document.write(sPrefix + this.color + sSuffix); }; var obj = new Object(); obj.color = "red"; sayColor.apply(obj,new Array("The color is ",", a very nice color indeed.")); //apply()方法第一个参数仍为obj,即应该赋予sayColor()中的this关键字的值 //第二个参数是父类其他参数组成的数组。此例说明apply()方法的用法 function ClassB(sColor, sName){ //对象冒充的前三行由一行代替 ClassA.apply(this, new Array(sColor)); //另外可以用 ClassA.apply(this, arguments); 将ClassB的整个arguments对象作为第二个参数传递给apply()方法,需参数顺序一致 this.name = sName; this.sayName = function(){ alert(this.name); }; } } //4、原型链方法 function extendsmethod4(){ function ClassA(){ } ClassA.prototype.color = "red"; ClassA.prototype.sayColor = function(){ alert(this.color); }; function ClassB(){ } ClassB.prototype = new ClassA(); //要确保ClassA的构造函数没有参数 ClassB.prototype.name = ""; //子类的所有属性和方法要在prototype属性被赋值之后 ClassB.prototype.sayName = function(){ alert(this.name); }; //测试 var objA = new ClassA(); var objB = new ClassB(); objA.color = "red"; objB.color = "blue"; objB.name = "Nicholas"; objA.sayColor(); objB.sayColor(); objB.sayName(); //对ClassB的所有实例使用 instanceof 为ClassA和ClassB 都返回true alert(objB instanceof ClassA); alert(objB instanceof ClassB); } //5、混合方式,此方法为最好的继承方式 function extendsmethod5(){ function ClassA(sColor){ this.color = sColor; } ClassA.prototype.sayColor = function(){ alert(this.color); }; function ClassB(sColor, sName){ ClassA.call(this, sColor); //用对象冒充继承ClassA类的sColor属性 this.name = sName; } ClassB.prototype = new ClassA(); //用原型链继承ClassA类的方法 ClassB.prototype.sayName = function(){ alert(this.name); }; //测试 var objA = new ClassA("red"); var objB = new ClassB("blue", "Nicholas"); objA.sayColor(); objB.sayColor(); objB.sayName(); }参考资料:JavaScript高级程序设计