Van Coding
Van Coding

Reputation: 24554

Javascript - Create instance with array of arguments

I know the possibility to call a function with an array of arguments with apply(obj,args); Is there a way to use this feature when creating a new instance of a function?

I mean something like this:

function A(arg1,arg2){
    var a = arg1;
    var b = arg2;
}

var a = new A.apply([1,2]); //create new instance using an array of arguments

I hope you understand what i mean... ^^^

Thanks for your help!

Solved!

I got the right answer. To make the answer fit to my question:

function A(arg1,arg2) {
    var a = arg1;
    var b = arg2;
}

var a = new (A.bind.apply(A,[A,1,2]))();

Upvotes: 28

Views: 12529

Answers (8)

dlporter98
dlporter98

Reputation: 1630

It can now be done using the spread operator:

let a = new A(...[1,2]);

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#examples

Upvotes: 0

Toufiqur Chowdhury
Toufiqur Chowdhury

Reputation: 1

I just had the same issue and also wanted to preserve prototype properties of the target object. After looking at the answers, just came up with a rather simple solution. Thought I might as well share it for any future seeker :)

// Define a pseudo object that takes your arguments as an array
var PseudoObject = function (args) {
    TargetObject.apply(this, args);
};
// if you want to inherit prototype as well
PseudoObject.prototype = new TargetObject();

// Now just use the PseudoObject to instantiate a object of the the OtherObject
var newObj = new PseudoObject([1, 2, 3]);

Upvotes: 0

Wilt
Wilt

Reputation: 44383

What if you have your object class name stored in a variable called className ?

var className = 'A'

According to this answer here it all becomes very clean and simple using ECMAScipt5's Function.prototype.bind method.

With an array of arguments:

new ( Function.prototype.bind.apply( className, arguments ) );

Or with an argument list:

new ( Function.prototype.bind.call( className, argument1, argument2, ... ) );

A single line, no need for a wrapper.

Upvotes: 0

inf3rno
inf3rno

Reputation: 26137

You can use Object.create() to build the new instance, and call the constructor on the instance after that:

var args = [1,2,3];
var instance = Object.create(MyClass.prototype);
MyClass.apply(instance, args);

or in a single line:

var instance = MyClass.apply(Object.create(MyClass.prototype), args);

but don't forget return this; in MyClass by this single line solution.

If you don't have Object.create(), then it is very simple to write one:

Object.create = function (source){
    var Surrogate = function (){};
    Surrogate.prototype = source;
    return new Surrogate();
};

You can optionally write an Function.newInstance() or a Function.prototype.newInstance() function:

Function.newInstance = function (fn, args){
    var instance = Object.create(fn.prototype);
    fn.apply(instance, args);
    return instance;
};

so var instance = Function.newInstance(MyClass, args);.

note: It is not recommended to override native classes.

Upvotes: 3

Jon Jaques
Jon Jaques

Reputation: 4410

@Raynos answer works well, except that the non-ES5 version is missing the constructor's prototype after instantiation.

Here's my updated cApply method:

var cApply = function(c) {
  var ctor = function(args) {
    c.apply(this, args);
  };
  ctor.prototype = c.prototype;
  return ctor;
};

Which can be used like this:

var WrappedConstructor = cApply(Constructor);
var obj = new WrappedConstructor([1,2,3]);

// or inline like this.    
var obj2 = new (cApply(Constructor))([1,2,3]);

JSFiddle for reference.

Upvotes: 6

sqykly
sqykly

Reputation: 1586

with ECMAscript 5 you can:

function createInstanceWithArguments (fConstructor, aArgs) {
    var foo = Object.create(fConstructor.prototype);
    fConstructor.apply(foo, aArgs);
    return foo;
}

Upvotes: 7

Raynos
Raynos

Reputation: 169451

var wrapper = function(f, args) {
    return function() {
        f.apply(this, args);
    };
};

function Constructor() {
    this.foo = 4;
}
var o = new (wrapper(Constructor, [1,2]));
alert(o.foo);

We take a function and arguments and create a function that applies the arguments to that function with the this scope.

Then if you call it with the new keyword it passes in a new fresh this and returns it.

The important thing is the brackets

new (wrapper(Constructor, [1,2]))

Calls the new keyword on the function returned from the wrapper, where as

new wrapper(Constructor, [1,2])

Calls the new keyword on the wrapper function.

The reason it needs to be wrapped is so that this that you apply it to is set with the new keyword. A new this object needs to be created and passed into a function which means that you must call .apply(this, array) inside a function.

Live example

Alternatively you could use ES5 .bind method

var wrapper = function(f, args) {
    var params = [f].concat(args);
    return f.bind.apply(f, params);
};

See example

Upvotes: 16

sdleihssirhc
sdleihssirhc

Reputation: 42496

You can curry the functions:

function A(arg1, arg2) {
    // ...
}

function A12() {
    A(1, 2);
}

You could even build a curry factory:

function A_curry() {
    var args = arguments;
    return function () {
        A.apply(null, args);
    };
}

Upvotes: 3

Related Questions