Use of .Apply() With 'New' Operator. Is This Possible

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 a TypeError 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



Leave a reply



Submit