Use of .apply() with 'new' operator. Is this possible?
With ECMAScript5's Function.prototype.bind
things get pretty clean:
function newCall(Cls) {
return new (Function.prototype.bind.apply(Cls, arguments));
// or even
// return new (Cls.bind.apply(Cls, arguments));
// if you know that Cls.bind has not been overwritten
}
It can be used as follows:
var s = newCall(Something, a, b, c);
or even directly:
var s = new (Function.prototype.bind.call(Something, null, a, b, c));
var s = new (Function.prototype.bind.apply(Something, [null, a, b, c]));
This and the eval-based solution are the only ones that always work, even with special constructors like Date
:
var date = newCall(Date, 2012, 1);
console.log(date instanceof Date); // true
edit
A bit of explanation:
We need to run new
on a function that takes a limited number of arguments. The bind
method allows us to do it like so:
var f = Cls.bind(anything, arg1, arg2, ...);
result = new f();
The anything
parameter doesn't matter much, since the new
keyword resets f
's context. However, it is required for syntactical reasons. Now, for the bind
call: We need to pass a variable number of arguments, so this does the trick:
var f = Cls.bind.apply(Cls, [anything, arg1, arg2, ...]);
result = new f();
Let's wrap that in a function. Cls
is passed as argument 0, so it's gonna be our anything
.
function newCall(Cls /*, arg1, arg2, ... */) {
var f = Cls.bind.apply(Cls, arguments);
return new f();
}
Actually, the temporary f
variable is not needed at all:
function newCall(Cls /*, arg1, arg2, ... */) {
return new (Cls.bind.apply(Cls, arguments))();
}
Finally, we should make sure that bind
is really what we need. (Cls.bind
may have been overwritten). So replace it by Function.prototype.bind
, and we get the final result as above.
Use of .apply() with 'new' operator. Is this possible?
With ECMAScript5's Function.prototype.bind
things get pretty clean:
function newCall(Cls) {
return new (Function.prototype.bind.apply(Cls, arguments));
// or even
// return new (Cls.bind.apply(Cls, arguments));
// if you know that Cls.bind has not been overwritten
}
It can be used as follows:
var s = newCall(Something, a, b, c);
or even directly:
var s = new (Function.prototype.bind.call(Something, null, a, b, c));
var s = new (Function.prototype.bind.apply(Something, [null, a, b, c]));
This and the eval-based solution are the only ones that always work, even with special constructors like Date
:
var date = newCall(Date, 2012, 1);
console.log(date instanceof Date); // true
edit
A bit of explanation:
We need to run new
on a function that takes a limited number of arguments. The bind
method allows us to do it like so:
var f = Cls.bind(anything, arg1, arg2, ...);
result = new f();
The anything
parameter doesn't matter much, since the new
keyword resets f
's context. However, it is required for syntactical reasons. Now, for the bind
call: We need to pass a variable number of arguments, so this does the trick:
var f = Cls.bind.apply(Cls, [anything, arg1, arg2, ...]);
result = new f();
Let's wrap that in a function. Cls
is passed as argument 0, so it's gonna be our anything
.
function newCall(Cls /*, arg1, arg2, ... */) {
var f = Cls.bind.apply(Cls, arguments);
return new f();
}
Actually, the temporary f
variable is not needed at all:
function newCall(Cls /*, arg1, arg2, ... */) {
return new (Cls.bind.apply(Cls, arguments))();
}
Finally, we should make sure that bind
is really what we need. (Cls.bind
may have been overwritten). So replace it by Function.prototype.bind
, and we get the final result as above.
Use apply with a function constructor
Of course it can be done. This is the one case where eval
turns out to be useful.
function newApply(cls, args) {
var argsAsString = [];
for (var i = 0, l = args.length; i < l; i++) {
argsAsString.push('args[' + i + ']');
}
return eval('new cls(' + argsAsString.join(',') + ')');
}
(stolen from another thread)
Use of .apply() with 'new' operator. Is this possible?
With ECMAScript5's Function.prototype.bind
things get pretty clean:
function newCall(Cls) {
return new (Function.prototype.bind.apply(Cls, arguments));
// or even
// return new (Cls.bind.apply(Cls, arguments));
// if you know that Cls.bind has not been overwritten
}
It can be used as follows:
var s = newCall(Something, a, b, c);
or even directly:
var s = new (Function.prototype.bind.call(Something, null, a, b, c));
var s = new (Function.prototype.bind.apply(Something, [null, a, b, c]));
This and the eval-based solution are the only ones that always work, even with special constructors like Date
:
var date = newCall(Date, 2012, 1);
console.log(date instanceof Date); // true
edit
A bit of explanation:
We need to run new
on a function that takes a limited number of arguments. The bind
method allows us to do it like so:
var f = Cls.bind(anything, arg1, arg2, ...);
result = new f();
The anything
parameter doesn't matter much, since the new
keyword resets f
's context. However, it is required for syntactical reasons. Now, for the bind
call: We need to pass a variable number of arguments, so this does the trick:
var f = Cls.bind.apply(Cls, [anything, arg1, arg2, ...]);
result = new f();
Let's wrap that in a function. Cls
is passed as argument 0, so it's gonna be our anything
.
function newCall(Cls /*, arg1, arg2, ... */) {
var f = Cls.bind.apply(Cls, arguments);
return new f();
}
Actually, the temporary f
variable is not needed at all:
function newCall(Cls /*, arg1, arg2, ... */) {
return new (Cls.bind.apply(Cls, arguments))();
}
Finally, we should make sure that bind
is really what we need. (Cls.bind
may have been overwritten). So replace it by Function.prototype.bind
, and we get the final result as above.
Use of .apply() with 'new' operator. Is this possible?
With ECMAScript5's Function.prototype.bind
things get pretty clean:
function newCall(Cls) {
return new (Function.prototype.bind.apply(Cls, arguments));
// or even
// return new (Cls.bind.apply(Cls, arguments));
// if you know that Cls.bind has not been overwritten
}
It can be used as follows:
var s = newCall(Something, a, b, c);
or even directly:
var s = new (Function.prototype.bind.call(Something, null, a, b, c));
var s = new (Function.prototype.bind.apply(Something, [null, a, b, c]));
This and the eval-based solution are the only ones that always work, even with special constructors like Date
:
var date = newCall(Date, 2012, 1);
console.log(date instanceof Date); // true
edit
A bit of explanation:
We need to run new
on a function that takes a limited number of arguments. The bind
method allows us to do it like so:
var f = Cls.bind(anything, arg1, arg2, ...);
result = new f();
The anything
parameter doesn't matter much, since the new
keyword resets f
's context. However, it is required for syntactical reasons. Now, for the bind
call: We need to pass a variable number of arguments, so this does the trick:
var f = Cls.bind.apply(Cls, [anything, arg1, arg2, ...]);
result = new f();
Let's wrap that in a function. Cls
is passed as argument 0, so it's gonna be our anything
.
function newCall(Cls /*, arg1, arg2, ... */) {
var f = Cls.bind.apply(Cls, arguments);
return new f();
}
Actually, the temporary f
variable is not needed at all:
function newCall(Cls /*, arg1, arg2, ... */) {
return new (Cls.bind.apply(Cls, arguments))();
}
Finally, we should make sure that bind
is really what we need. (Cls.bind
may have been overwritten). So replace it by Function.prototype.bind
, and we get the final result as above.
How can I call a javascript constructor using call or apply?
Try this:
function conthunktor(Constructor) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var Temp = function(){}, // temporary constructor
inst, ret; // other vars
// Give the Temp constructor the Constructor's prototype
Temp.prototype = Constructor.prototype;
// Create a new instance
inst = new Temp;
// Call the original Constructor with the temp
// instance as its context (i.e. its 'this' value)
ret = Constructor.apply(inst, args);
// If an object has been returned then return it otherwise
// return the original instance.
// (consistent with behaviour of the new operator)
return Object(ret) === ret ? ret : inst;
}
}
Applying new operator to Shape.call(o)
If you just want to apply the function to the object, you don't have to use new
. Just do Shape.call(o)
.
If you wanted o
to also inherit from Shape.prototype
, then you cannot go this path anyway. There is no standard way to change the prototype of an existing object. You could either pass o
as argument to Shape
and copy the properties or use Object.create
:
var o = Object.create(Shape.prototype);
o.p = 'p';
Shape.call(o);
Why I cant to use new in this case?
new Shape.call(o)
is evaluated as (new Shape.call)(o)
. The new operator throws an error if the operand (Shape.call
) doesn't have an internal [[Constructor]]
property:
If constructor does not implement the
[[Construct]]
internal method, throw aTypeError
exception.
Usually every function has this internal property, but the specification explicitly states:
None of the built-in functions described in this clause that are not constructors shall implement the
[[Construct]]
internal method unless otherwise specified in the description of a particular function.
Function.prototype.call
is a built-in function, not a constructor, and hence doesn't have a [[Construct]]
property.
Create instance without `new` operator with variable argument list
If you don't mind using ECMAScript 5 functions, Object.create()
could help:
function Point()
{ var args = Array.prototype.slice.call(arguments);
if (this instanceof Point) return Point.apply(null, args);
var pos = XY(args);
var result = Object.create(Point.prototype);
result.x = pos.x;
result.y = pos.y;
return result;
}
If you need ECMAScript 3 compatibility, this crazy, convoluted solution is yet another one (note that it's just a wrapper for an internal equivalent of new Point
):
function Point()
{ var pos = XY(Array.prototype.slice.call(arguments));
function internalPoint()
{ this.x = pos.x;
this.y = pos.y;
}
internalPoint.prototype = Point.prototype;
return new internalPoint;
}
Related Topics
Can't Perform a React State Update on an Unmounted Component
JavaScript: Difference Between .Foreach() and .Map()
How to Determine If a Variable Is 'Undefined' or 'Null'
How to Set File Input Value When Dropping File on Page
How to Use JavaScript Conditionally Like CSS3 Media Queries, Orientation
Jquery or JavaScript - How to Disable Window Scroll Without Overflow:Hidden;
Include a JavaScript File in Shiny App
What Does It Mean Global Namespace Would Be Polluted
Jqgrid Server Side Error Message/Validation Handling
How Does This JavaScript/Jquery Syntax Work: (Function( Window, Undefined ) { })(Window)
How to Parse a CSV String With JavaScript, Which Contains Comma in Data
Using Node.Js Require Vs. Es6 Import/Export
What Are Alternatives to Document.Write
Programmatically Changing Webkit-Transformation Values in Animation Rules
Disable Elastic Scrolling in Safari