Search code examples
javascriptinheritanceconstructoriife

Passing arguments to a Javascript IIFE constructor


I'm trying to get my head around Javascript OO, using the IIFE module pattern to mimic a class:

var MyClass = (function() {
  // Constructor
  return function() {
    return {
      foo: 'foo'
    }
  }
}());

I'm passing arguments with something like:

var MyClass = (function() {
  // Constructor
  return function(arg) {
    return {
      foo: function() {
        return 'foo'+arg
      }
    }
  }
}());

To mimic classical inheritance I am using the pattern suggested here:

function inherit(base, child, obj) {
  child.prototype = Object.create(base.prototype);
  child.prototype.constructor = child;
  obj&&Object.keys(obj).forEach(function(key){
    child.prototype[key] = obj[key];
  })
}

var Base = (function() {

  var init = function() {};

  init.prototype = {
    foo: function() {
      return "foo";
    }
  };

  return init;

}());

var Child = (function() {

  var init = function() {
    Base.call(this); 
  };

  inherit(Base, init, {
    bar: function() {
      return 'bar';
    }
  });

  return init;

}());

So far so good. My only problem is in understanding how to pass parameters to my class constructor when I'm doing inheritance in the above way. I like the fact that in the 'pure' IIFE module I can simply refer to the constructor parameter in any functions defined within it, so that they become closures. But how do I access constructor params when I'm adding these subsequent functions using the constructor variable, as in the inheritance example above? I suppose I could do something like:

var init = function(arg) {
  this.theArg = arg;
};

Then I can access it within anything subsequent:

init.prototype = {
    foo: function() {
      return "foo"+this.theArg;
    }
  };

And for the child:

var init = function(arg) {
    Base.call(this, arg); 
  };

This makes arg available to the outside world, so to make it read-only I suppose a getter would work:

var init = function(arg) {
    var theArg = arg;
    this.getArg = function() { return theArg };
  };

On the face of it I can't see anything wrong with that, and I can't think of a better alternative. Is there one? Am I missing something obvious?


Solution

  • I can't think of a better alternative. Is there one?

    No. Not in your example.

    I like the fact that in the 'pure' IIFE module I can simply refer to the constructor parameter in any functions defined within it, so that they become closures.

    You can access args in each function because, in your first example, you are defining foo on each object instance separately. Therefore each definition of foo has a separate closure containing the args passed when it was defined.

    This is also only possible, because foo is defined within the scope containing your args.

    But how do I access constructor params when I'm adding these subsequent functions ... in the inheritance example above?

    By using the classical inheritance patten you found, you are now defining the foo function on the constructor prototype. This means that only a single foo definition exists which is inherited by all instances created using your constructor. So foo can not be made specific to each instance anymore.

    As you have figured, it also means foo is no longer defined inside the scope containing args and has no direct access.

    You are therefore correct by assigning args to this.thisArgs which allows foo to access thisArgs on each instance. You have made foo a general case function that can handle any instance it is applied to.

    Passing arguments to the IIFE constructor: The IIFE itself is not the constructor, it simply builds the constructor object. The IIFE's scope has long since been returned by the time the constructor itself is invoked.

    Am I missing something obvious?

    Yes. Javascript is a prototypical language. It was never meant to be like "classical" languages. Just let it be Javascript. :)