日期:2014-05-16  浏览次数:20358 次

继承体系 --class.js

//继承
 //实现singlaton
 //可以调用基类函数
 //JavaScript通过构造函数和原型的方式模拟实现了类的功能。
  
 
  var Class = (function(){
 
     //IE不会遍历几个特殊属性:"constructor", "toString", "valueOf"
      var IS_DONTENUM_BUGGY = void function(){
         for (var p in { toString: 1}) return false;
         return true;
     }(); 
     function create(options){
         var options = options || {}, uniqueInstance = null;
         //判定是否需要实现单例
          var singleton = !!options.singleton;
         delete options.singleton;
         //父类
         var superclass = options.inherit || {};
         delete options.inherit;
         
         function klass(){
             if (!singleton)  this.init.apply(this, arguments);
         }
         //添加类方法
         $U.extend(klass, Class.Methods);
         //是否继承
         if ($U.isFunction(superclass)) {
             var bridge = function(){};
             bridge.prototype = superclass.prototype;
             klass.prototype = new bridge;
             klass.superclass = superclass;
         }
         //添加原型方法
         klass.addMethods(options);
         
         if (!klass.prototype.init) 
             klass.prototype.init = function(){
             };
         //修正constructor    
         klass.prototype.constructor = klass;
         //__proto__是什么?我们在这里简单地说下。每个对象都会在其内部初始化一个属性,就是__proto__,当我们访问一个对象的属性时,如果
         //这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性,这个__proto__又会有自己的__proto__,于是就这样
         //一直找下去,也就是我们平时所说的原型链的概念。
         //按照标准,__proto__是不对外公开的,也就是说是个私有属性,但是Firefox的引擎将他暴露了出来成为了一个共有的属性,
         //我们可以对外访问和设置。
         
         //修复IE与Opera中的第二条原型链
         if (!klass.prototype.__proto__) klass.prototype.__proto__ = klass.prototype;
         
         
         //处理函数:如果singleton模式,则private constructor
         return singleton ? {
             getInstance: function(){
                 if (!uniqueInstance) {// Instantiate only if the instance doesn't exist.
                     uniqueInstance = new klass;
                     uniqueInstance.init.apply(uniqueInstance, arguments);
                 }
                 return uniqueInstance;
             }
         } : klass;
     }
     function addMethods(source){
         var ancestor = this.superclass && this.superclass.prototype, properties = $U.keys(source);
         //处理IE不能遍历的特殊属性。
         if (IS_DONTENUM_BUGGY) {
             if (source.toString != Object.prototype.toString) 
                 properties.push("toString");
             if (source.valueOf != Object.prototype.valueOf) 
                 properties.push("valueOf");
         }
         for (var i = 0, length = properties.length; i < length; i++) {
             var property = properties[i], value = source[property];
             //在C#中,如果子类有意隐藏基类成员,使用关键字"new"
             //使用base关键字显示调用基类构造函数
             //这这里约定如果子类方法第一个参数是“$super”,则调用父类的方法.
             if (ancestor && $U.isFunction(value) && (value.argumentNames()[0] === "$super")) {
                 var method = value;
                 //var f = (function(m){ return function(){ return ancestor[m].apply(this, arguments)}})(property)
                 //f.wrap(method)
                 
                 //F.prototype[name] = (function(name, fn) {
                 //    return function() {
                 //        var that = this;
                 //        $super = function() {
                 //            return baseClass.prototype[name].apply(that, arguments);
                 //        };
                 //        return fn.apply(this, Array.prototype.concat.apply($super, arguments));
                 //    };
                 //})(name, prop[name]);
                 
                 
                 //总之,实现把基类函数作为子函数的第一个参数,以此调用父函数。
                 value = ancestor[property].wrap(method);
                 value.valueOf = method.valueOf.bind(method);
                 // 因为我们改变了函数体,所以重新定义函数的toString方法
                 // 这样用户调用函数的toString方法时,返回的是原始的函数定义体