var A = function(){
    var name = null;
    this.setName = function(_name){
        name = _name;
    }
}
var B = function(){
    A.call(this);   //相当于super(),A是B的父类
    this.setName = function(_name){
        //这里想调用父类的setName
        alert("this is class B");
    }
}
extends(B, A);   //继承原型链
在这个代码里,非常纠结,为了让name成为私有变量,使用了闭包的办法,但是后果就是setName函数只能写到this里,而不能写到原型链里,所以在子类B的setName函数里想要调用A里的setName函数就杯具了。
怎么破?

解决方案 »

  1.   

    只有比较丑陋的做法,在父类中setName的逻辑放到_setName这个函数中
    然后setName只是简单调用_setName然后子类调用父类的方法也是调用_setName
      

  2.   

    或者说只有这种解决方法
             var A = function(){
    var _name = null;
    this._setName = function(name){
    _name = name;
    }
    this._getName = function(){
    return _name;
    }
    }
    A.prototype.setName = function(name){
    this._setName(name);
    }

    A.prototype.getName = function(){
    return this._getName();
    }

    var B = function(){
    var _sex;
    A.call(this);

    }
    qq.html.extend(B, A);

    B.prototype.setName = function(name){
    A.prototype.setName.call(this, name);
    }


    var b = new B();
    b.setName("aaa");
    alert(b.getName());
      

  3.   

    刚好我自己写了一个类的扩展机制,你可以试试
    <html>
        <head>
            <title></title>
    <script type="text/javascript" language="javascript">
    /************************/
    /* 类继承机制的简单实现 */
    /************************/
    (function () {
        function BaseRef() {
            this.members = {};
            this.memberPoint = {};
        }
        BaseRef.prototype = (function () {
            function addMember(name, mb) {
                var baseMember = null;
                if (this.members[name] != null) {
                    baseMember = this.members[name];
                }
                this.members[name] = { method: mb, base: baseMember };
            }
            function clone() {
                var newRef = new BaseRef();
                for (var attr in this.members) {
                    newRef.members[attr] = this.members[attr];
                }
                return newRef;
            }
            return {
                addMember: addMember,
                clone: clone
            };
        })();    function callBase() {
            var funName = arguments[0];
            var args = [];
            for (var i = 1; i < arguments.length; i++) {
                args.push(arguments[i]);
            }
            var br = this._base;
            var point = br.memberPoint[funName];
            if (point == null) {
                point = br.members[funName];
            }
            var fun = point.method;
            br.memberPoint[funName] = point.base;
            try {
                fun.apply(this, args);
            }
            catch (err) { alert(err); }
            br.memberPoint[funName] = point;
        }    Function.prototype.Extend = function (baseCls, proto) {
            for (var attr in baseCls.prototype) {
                //复制基类的prototype
                if (attr == "_base") {
                    this.prototype[attr] = baseCls.prototype[attr].clone();
                    continue;
                }
                this.prototype[attr] = baseCls.prototype[attr];
            }
            for (var attr in proto) {
                if (this.prototype[attr] != null) {
                    //出现同名成员,作重载操作处理
                    var oldMember = this.prototype[attr];
                    if (this.prototype["_base"] == null) {
                        this.prototype["_base"] = new BaseRef();
                    }
                    var br = this.prototype["_base"];
                    br.addMember(attr, oldMember);
                }
                this.prototype[attr] = proto[attr];
            }
            this.prototype.callBase = callBase;
        }
    })();
    </script>
    <script type="text/javascript" language="javascript">
        //基类
        function Cls0(){
            this.name="这是基类";
        }
        Cls0.prototype={
            ShowMe:function(){
                alert(this.name);
            }
        };
        
        //子类
        function Cls1(){
            //调用父类构造函数
            Cls0.call(this);
            this.name+="(子类添加的内容)";
        }
        Cls1.Extend(Cls0,{
            ShowMe:function(){
                alert("即将调用父类方法");
                this.callBase("ShowMe");
            }
        });
        
        var inst=new Cls1();
        inst.ShowMe();
    </script>
        </head>
        <body>
            
        </body>
    </html>
      

  4.   

    很简单,假设你包装了一个DIV类,里面保存了width, height等对象
    var Div = function(){
        this.width = 0;
        this.height = 0;
        this.dom = document.createElement("div");
    }而你设置width和height的时候,不光要改变width和height的变量,还得修改dom的style,所以你不能允许用户直接new Div().width = 45,因为这样dom对象的style并没有被修改,所以我们需要用闭包把width对象保护起来,而不能放到this里。所以需要一个wapper来setWidth,而不是直接修改width属性,这就是私有变量。接下来我需要扩展DIV类, 里面除了这个div之外,还有另外一个重叠的div,现在setWidth需要做三件事,1:设置width变量,2:设置第一个div的style,3:设置第二个div的style,前两个都可以通过调用父类的setWidth实现,而第三个则需要调用父类的setWidth之后再进行设置。
    这就是java,c++等语言最常用的情况了。
    这个例子有些傻,但是实际中有很多这种需要,不要说width和height每次从style里去读,第一是性能,第二是canvas的变换矩阵只能自己计算,保存一个变量,而不能从CanvasContext里去取
      

  5.   

    你的意思是像java一样,子类只能通过父类的方法访问父类的私有属性?不管你的意思如何,你的写法本身存在一些问题var B = function(){
        //相当于super(),A是B的父类    
        A.call(this);   
        //这时候this.setName已经存在,你再这样写是覆盖了继承过来的setName
        this.setName = function(_name){
            //这里想调用父类的setName
            alert("this is class B");
        }
    }
      

  6.   

    谢谢啊,兄弟的方法对我很有启发,但是有个关键的问题解决不了。
    就是说父类的方法为了保存私有变量,是在构造函数定义到this里的,所以子类继承的方式不是继承prototype里的属性。
    而是在实例化对象的时候,在构造函数里通过apply或者call修改this指针调用父类的构造函数。而这一步必须放到构造函数的最开头,因为后面自定义的函数可能会调用这些继承的函数。这个时候根本无法知道是否有函数重名
      

  7.   


    var A = function(){
        var name = null;
        this.setName = function(_name){
            name = _name;
        }
    }为什么要用这种方式来定义setName而不用prototype呢?虽然运行效果是一样的,但这种方式相当于每创建一个实例,就会产生一段相同的代码 function(_name){   name = _name;  },但prototype的话,不管是多少个实例,都会使用同一个function
      

  8.   

    这就是我5楼解释的问题,写到prototype里的话就无法保护私有变量了。
      

  9.   

    var A = function(){
        var name = null;
        this._setName = function(_name){
            name = _name;
        }
    }
    A.prototype={
        setName:function(name){
            this._setName(name);
        }
    }这样如何?然后子类继承setName。虽然多了一层,但似乎能解决你的问题
      

  10.   


    这就是我3楼的方案啊,目前我能想到最靠谱的就是这个,当然,如果追求完美的话有2个缺点:
    1。 基类比较丑,多了一层调用,多了一层性能开销
    2。 无法阻止子类直接调用_setName,如果在setName里判断caller名称不是setName就报异常的话大部分情况多了一层判断,感觉有点亏
      

  11.   

    你想要的效果可以用原型继承来解决,但原型继承存在另外一些问题,即一个子类改变了父类的属性,另外一个子类会受到影响        var A = function(){
        var name = null;
        this.setName = function(_name){
            name = _name;
            alert("in class a");
        }
        this.getName = function(){
         return name;
        }
    }

    var B = function(){
    this.setName = function setName(_name){
    var proto = this.constructor.prototype;
    proto[arguments.callee.name](_name);
    alert("in class b");
    }
    }

    B.prototype = new A();
    B.prototype.constructor = B;
    var b = new B();
    b.setName("bbb");
    alert(b.getName());
      

  12.   


    OOP框架:Fan v1.3.70 完全模拟java的面向对象编程
    /**
     * Fan
     *
     * @version 1.3.70
     *
     * @author FuFan
     * 
     * @date 2011/11/10
     *
     * OOP部分使用范例:
     * 
     */
      //  [创建接口]
           Fan.interface('Fan.test.IA', function(){
               this.INFO = 'Fan.test.IA';
               this.showA = Function;
           });
           
           Fan.interface('Fan.test.IB', function(){
               this.INFO = 'Fan.test.IB';
               this.showB = Function;
           });
        
       //  [接口继承]  
           Fan.interface('Fan.test.IC', Fan.test.IB, Fan.test.IA, function(){
               this.INFO = 'Fan.test.IC';
               this.showC = Function;
           });
        
       //  [创建类] 默认继承Object
           Fan.clazz('Fan.test.DImpl', function(){
               var _d;
               this.DImpl = function(d){
                this.$super();
                _d = d;
               };
               
               this.showA = function(){
                   return _d;
               };
           });
           
       //  [类继承]
           Fan.clazz('Fan.test.EImpl', Fan.test.DImpl, function(){
            //alert('2:' + cfg);
               this.a = null;
               this.b = null;
               this.c = null;
               
               this.EImpl = function(cfg){
                this.$super(cfg.d); // 带参数调用父类构造方法
                this.a = 'EImpl.a';
                   this.b = cfg.b;
                   this.c = cfg.c;
               };
        
               this.showA = function(){
                   return this.a;
               };
          });
        
      //  [类继承+实现接口]
    Fan.clazz('Fan.test.FImpl', Fan.test.EImpl, Fan.test.IC, Fan.test.IB,fnction(){
         this.a = 'FImpl.a';
              
         this.FImpl = function(cfg){
              this.$super(cfg);
                };
       
          this.showA = function(){
              return this.a;
          };
          this.showB = function(){
               return this.b;
          };
          this.showC = function(){
              return this.c;
          };
          this.showF = function(){
             return 'Fan.test.FImpl';
          };
      });
       
      //  [使用]
      f = new Fan.test.FImpl({a:'aa', b:'bb', c:'cc', d:'dd'});
      Logger.info('f.showA() == ' + f.showA());
      if(f.showA() == 'FImpl.a'){
          Logger.info('子类调用正常');
      } else {
          Logger.error('子类调用异常');
      }
     
      //  [类型鉴别]
           if(f instanceof Fan.test.FImpl 
             && f instanceof Fan.test.EImpl 
             && f instanceof Fan.test.DImpl 
             && f instanceof Object         
             && f.$super instanceof Fan.test.EImpl
             && Fan.instance(f, Fan.test.IA)
             && Fan.instance(f, Fan.test.IB)
             && Fan.instance(f, Fan.test.IC)) {
                 Logger.info('类型鉴别正常');
           }
           else{ 
                Logger.error('类型鉴别异常');
           }
     
      //  [父类句柄]
      Logger.info('f.$super.showA() == ' + f.$super.showA());
      Logger.info('f.$super.$super.showA() == ' + f.$super.$super.showA());
      if(f.$super.showA() == 'EImpl.a' && f.$super.$super.showA() == 'dd'){
          Logger.info('父类调用正常');
           } else {
            Logger.error('父类调用异常');
           }