Reputation: 24554
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
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
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
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
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
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
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
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
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