首页 > 代码库 > js 类工厂
js 类工厂
js中的类工厂就是因为js中一直没有真正的类。创建类工厂是为了模拟类,类工厂的主要部分就是prototype的扩展和返回一个基本的用来new的函数
prototype扩展
首先是prototype的扩展,可以用一个简单的for...in...循环来实现。
for(var item in from){ if(from.hasOwnProperty(item)){ target[item] = from[item]; } }
但是自从有getOwnPropertyDescriptor后,我们就有了一个更好的方法来拷贝prototype中的属性。通过getOwnPropertyDescriptor函数,可以将prototype的属性中[[writable]],[[enumerable]]等等属性都取到,然后通过defineProperty方法将其设置到新的prototype中。
不过要考虑兼容老版本的浏览器,于是要对浏览器是否支持getOwnPropertyDescriptor作一个判断,最后的函数如下:
function mixpro(target,from){ if(Object.getOwnPropertyDescriptor){ Object.keys(from).forEach(function(property){ Object.defineProperty(target, property, Object.getOwnPropertyDescriptor(from, property)); }) }else{ for(var item in from){ if(from.hasOwnProperty(item)){ target[item] = from[item]; } } } };
主要定义的函数extend
在这里需要定义一个函数,用于返回一个基本的函数,用于后面的实例化。由于考虑到后面的继承父类,我们要引入一个参数,在需要时禁止init的运行,代码如下:
var Base = function(){ if(!is_init && this.init){ var old_super = this.super; this.super = _super; this.init.apply(this,arguments); this.super = old_super; } };
然后就是其中的super问题了,即在运行init的时候,让其可以调用到父类的属性(通过this.super.propertyName),于是就要得到对父对象prototype的引用。
var _super = this.prototype;
然后就是函数中将父元素的方法继承下来,然后在混入自己定义的方法:
is_init = true; proto = new this(); is_init = false; mixpro(proto, definition);
最后再进行一系列对象引用位置的调整,得到最后函数:
var extend = Class.extend = function(definition){ if(typeof definition !== ‘object‘){ return; } var _super = this.prototype; is_init = true; proto = new this(); is_init = false; mixpro(proto, definition); var Base = function(){ if(!is_init && this.init){ var old_super = this.super; this.super = _super; this.init.apply(this,arguments); this.super = old_super; } }; Base.prototype = proto; Base.prototype.constructor = Base; Base.extend = arguments.callee; return Base; };
完整的代码:
(function(global){ var Class,is_init = false,proto; Class = function(){}; function mixpro(target,from){ if(Object.getOwnPropertyDescriptor){ Object.keys(from).forEach(function(property){ Object.defineProperty(target, property, Object.getOwnPropertyDescriptor(from, property)); }) }else{ for(var item in from){ if(from.hasOwnProperty(item)){ target[item] = from[item]; } } } }; var extend = Class.extend = function(definition){ if(typeof definition !== ‘object‘){ return; } var _super = this.prototype; is_init = true; proto = new this(); is_init = false; mixpro(proto, definition); var Base = function(){ if(!is_init && this.init){ var old_super = this.super; this.super = _super; this.init.apply(this,arguments); this.super = old_super; } }; Base.prototype = proto; Base.prototype.constructor = Base; Base.extend = arguments.callee; return Base; }; global.Class = Class; })(window);
<方式继承
在司徒正美的书中有看到用<号来实现继承,这个原理就是<号出现会对两边求值,如果非基本变量的话,会先尝试调用其valueOf函数,若不能得到基本变量,就会调用toString,如果我们改写valueOf函数,就可以在内部实现继承了
至于如何实现,啊我懒得写了。。。。。