tusharmath
tusharmath

Reputation: 11002

Dynamically control arguments while creating objects in javascript

I have multiple eatable classes in javascript eg: food, drinks, snacks. Each of this class requires a different set of parameters. I have another factory class which creates an instance of the eatable item that is sent to it.

I am not able to figure out how can we dynamically select the eatable item and pass the arguments (which are in an array form) using this factory?

I have come up with two solutions - Solution 1:

var factory = function(eatable, argumentList){
  var obj = new eatable(argumentList);
  return obj
};

This is a problem because argumentList is an array.

Solution 2

var factory = function(eatable, argumentList){
  var obj =  eatable.apply({}, argumentList);
  return obj
};

this does not really create an object of the eatable type.

The effect that I really want Say I am able to convert the argumentList into a js argument type object then -

var obj = new eatable(argumentList.toArguments());
obj instanceOf eatable; // should return true

Please help!

Upvotes: 3

Views: 683

Answers (5)

tusharmath
tusharmath

Reputation: 11002

One more way to achieve this is as follows -

var _bind = Function.prototype.bind;
var factory = function(_constructor, _argumentList){
  var obj = _bind.apply(_constructor, [null].concat(_argumentList));
  return obj
};

Upvotes: 0

Aadit M Shah
Aadit M Shah

Reputation: 74234

Ah, yes. I've encountered this problem before - you can't use new and apply together in JavaScript. A similar question has been asked before: Use of .apply() with 'new' operator. Is this possible?

The problem is quite apparent - new is a keyword, not a function; and apply can only be used on a function. If new was a function instead of a keyword then we could use it in conjuction with apply.

To understand how to do so let's create a function called new which does exactly what the keyword new does:

Function.prototype.new = (function () {
    function Factory(constructor, args) {
        return constructor.apply(this, args);
    }

    return function() {
        Factory.prototype = this.prototype;
        return new Factory(this, arguments);
    };
}());

Now instead of calling a constructor as follows:

var object = new constructor(arg1, ...);

You can call a constructor as follows:

var object = constructor.new(arg1, ...);

What's the advantage of doing so you ask? Well it's simple really. Because new is now a function instead of a keyword you can use it in conjunction with apply as follows:

var object = Function.new.apply(constructor, [arg1, ...]);

Hence your eatable factory function now becomes:

var factory = function(eatable, argumentList) {
    var obj = Function.new.apply(eatable, argumentList);
    return obj;
};

Edit: If all your factory function does is take an eatable constructor and an argumentList and return new.apply(eatable, argumentList) then as Bergi pointed out in his comment you could define factory as follows instead:

var factory = Function.apply.bind(Function.new);

Hope this helped.

Upvotes: 4

Bergi
Bergi

Reputation: 665276

You can use Object.create to set up the prototype chain correctly:

function factory(eatable, argumentList){
    var obj = Object.create(eatable.prototyope);
    return eatable.apply(obj, argumentList) || obj;
}

This is basically what the new operator does.

Upvotes: 3

Diode
Diode

Reputation: 25165

You can define a function init to initialize the object .

function Eatable(){

}

Eatable.prototype.init = function(/** arg1, arg2, arg3 **/){
    //  initialize object
}

In factory function

var eatable = new Eatable();
eatable.init.apply(eatable, /** pass arguments array here **/);
return eatable;

Upvotes: 1

raam86
raam86

Reputation: 6871

You have to provide context to apply, The context is the object you are trying to apply the arguments to. The context you are currently passing {} is of type Object

var factory = function(eatable, argumentList){
  var obj =  eatable.apply(new Eatable(), argumentList);
  return obj
};

I can not use factories with out polymorphism so if you didn't create those eatables in way they extend an Eatalbe object you will not be able to do it.

Upvotes: 0

Related Questions