Search code examples
javascriptconstructorsubclassing

Subclass factory missing prototype - Javascript


I'm trying to create a factory function which accepts a superclass and a function as arguments, and returns a constructor for a subclass which overrides and applies a filter to the add() method.

The problem I'm getting is when I use this constructor to create this subclass object and invoke add(), the add() method isn't recognised.

If it helps I'm trying to use techniques similar to section 9.7.2 from Javascript - The definitive guide by David Flanagan.

Appreciate any help, thanks.

function subclassFactory(superclass,func){
     var constructor = function(){
        superclass.apply(this,arguments);    

        var proto = constructor.prototype 
                  = Object.create(superclass.prototype);
        proto.constructor = constructor; 

        proto.add = function(){
             if(!func(arguments)) 
             {
              return superclass.prototype.add.apply(this,arguments);
             } 
         }
     }

     return constructor;
  }

Solution

  • Don't modify the prototype inside the constructor.

    And please (as a rule of thumb) never ever pass the arguments-object to any function. You'd want to avoid passing the arguments-object to another function. It prevents the optimization through the underlying JS-engine. Use the spread-operator instead (ES6 Rest parameters @ MDN) or copy the Arguments manually into an Array.

    function subclassFactory(superclass, func){
        var constructor = function(/*...args*/){
            //for(var i=arguments.length,args=Array(i);i--;)args[i]=arguments[i];
            //return superclass.apply(this, args);
            return superclass.apply(this, arguments);
        }
    
        constructor.prototype = Object.create(superclass.prototype, { 
            constructor: { 
                configurable: true, 
                value: constructor 
            },
            add: { 
                value: function(/*...args*/){
                    for(var i=arguments.length,args=Array(i);i--;)args[i]=arguments[i];
                    if(!func(args)) return superclass.prototype.add.apply(this, args);
                }
            }
        });
    
        return constructor;
    }
    

    Or utilizing ES6-Classes (Classes#Mix-ins @ MDN)

    var subclassFactory = (superclass, func) => class extends superclass {
        add(...args){  
            if(!func(args)) return super.add.apply(this, args);
        }
    }