javascript框架之继承机制

来源:互联网 发布:原价打折怎么算法 编辑:程序博客网 时间:2024/05/22 08:08
大一点的框架都有这个东西。Prototype原来的继承机制非常弱,为了与mootools对抗也强化了这一方面。嘛,要用原型继承来模仿类继承,都基本存在一个克隆函数。把父类的原型属性复制到子类上去。理念的东西暂时这么多,动手实践一下最实际。我们设计一个数组类,拥有原生数组的能力与新扩展的能力。 var isNumber = function(n){ return typeof n === 'number' && isFinite(n); } var vArray = function(){ if(arguments.length == 0){ return []; }else if(arguments.length == 1 && isNumber(arguments[0])){ return new Array(arguments[0]); }else if(arguments.length > 1){ return Array.prototype.slice.apply(arguments); } } var a = vArray(); alert(a); var b = vArray(7); alert(b); var c = vArray(1,3,"司徒正美",true); alert(c); 运行代码很显然这是工厂方法,生成的原生数组,如果要扩展而不污染原生数组就又要再加一重包装。我们看继承是怎样实现的。这涉及到两个类,原生数组类与新数组类。先看代码: var Parent = function(){}; Parent.prototype = Array.prototype; var Array2 = function(){}; Array2.prototype = new Parent; Array2.prototype.newMethod = function(){ return "newMethod"; }; Array2.prototype.constructor = Array2; var a = new Array2("dd",4); alert(a.newMethod) var b = new Array("dd",4); alert(b.newMethod) 运行代码由于javascript的原型链的关系,我们不能直接var Array2 = Array;var a = new Array2;这样一旦从Array2的原型添加新方法(添加方法都建议往原型里加,不建议做成类方法)时,Array的原型也被加上了,因为它们是在同一条船上。我们必须断开它们。于是我们需要一个Parent函数做桥接。我们可以说Array为目标父类,Parent为真正父类。先把目标父类的原型赋给Parent的原型,这样Parent就拥有其所有公开的方法,然后我们再把这些方法赋给Array2。但这时Array2的实例的constructor 仍为原生的数组,我们要修正一下,也就是把它的原型上的constructor属性指向自己(Array2)即可(原来是Array)。我们可以参见下图看Prototype与constructor的关系。我们再把部分代码抽取出来做成一个方法: var makeBridge = function(klass) { var bridge = function() {}; bridge.prototype = klass.prototype; return new bridge; } Array2 = function(){}; Array2.prototype = makeBridge(Array); Array2.prototype.constructor = Array2;我们再看如何添加新属性与方法。 _mixin = function(/*Object*/ obj, /*Object*/ hash){ var nil = {}; //取出dojo,是我看过的所有浅复制方法中最谨慎的 //首先设置一个空对象,那么它的nil[i]方法肯定来自其原型Object.prototype //确保扩展包hash中的方法或属性在与Object.prototype的不一样, //或者是未定义,才能添加 for(var x in hash){ if(nil[x] === undefined || nil[x] != hash[x]){ obj[x] = hash[x]; } } // 在IE不能通过for...in循环中添加toString方法 if(!+"/v1" && hash){ var p = hash.toString; if(typeof p == "function" && p != obj.toString && p != nil.toString && p != "/nfunction toString() {/n [native code]/n}/n"){ obj.toString = hash.toString; } } return obj; // Object }; var makeBridge = function(klass) { var bridge = function() {}; bridge.prototype = klass.prototype; return new bridge; } Array2 = function(){}; Array2.prototype = makeBridge(Array) _mixin(Array2.prototype,{ newMethod : function(){ return "newMethod" }, newMethod2 : function(){ return "newMethod2" }, constructor: Array2 }) var a = new Array2("dd",4); for(var i in a){ alert(i + " " + a[i])//在IE不能遍历出constructor属性 } 运行代码上面的_mixin方法是最常见的继承方法,早期的Prototype也是依靠来拷贝原型方法,堂而皇之地称之为extend,而且什么也情况也不考虑。在Ext这里分成几种情况apply,applyif,override。在mootools中则叫add。好了,我们来考虑如何访问父类方法(我们可以通过重载方法来区分哪是子类方法,哪是父类方法)。要想访问父类方法,就必须能访问父类,我们把父类的名称保存在子类原型的一个属性即可。我们把makeBridge方法扩展一下,更名为inherit。 _mixin = function(/*Object*/ obj, /*Object*/ hash){ var nil = {}; //取出dojo,是我看过的所有浅复制方法中最谨慎的 //首先设置一个空对象,那么它的nil[i]方法肯定来自其原型Object.prototype //确保扩展包hash中的方法或属性在与Object.prototype的不一样, //或者是未定义,才能添加 for(var x in hash){ if(nil[x] === undefined || nil[x] != hash[x]){ obj[x] = hash[x]; } } // 在IE不能通过for...in循环中添加toString方法 if(!+"/v1" && hash){ var p = hash.toString; if(typeof p == "function" && p != obj.toString && p != nil.toString && p != "/nfunction toString() {/n [native code]/n}/n"){ obj.toString = hash.toString; } } return obj; // Object }; function inherit(subClass, superClass) { var bridge = function() {}; bridge.prototype = superClass.prototype; subClass.prototype = new bridge; subClass.prototype.constructor = subClass; subClass.prototype.superclass = superClass; return subClass; } var Animal = function(){ this.name = "动物"; }; var Tiger = function(){} Tiger = inherit(Tiger,Animal) _mixin(Tiger.prototype,{ name : "老虎", description:"独居肉性大型猫科动物" //这样这里不样重置构造器了 }) var t = new Tiger(); alert(t.name) alert(t.description) var s = new t.superclass alert(s.name) 运行代码但是这样做还是不爽,因为我们还是需要手动设置var Tiger = function(){}这个空函数,这个下回再说。本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/cheng5128/archive/2009/11/06/4779332.aspx