Use of .apply() with 'new' operator. Is this possible? - javascript

In JavaScript, I want to create an object instance (via the new operator), but pass an arbitrary number of arguments to the constructor. Is this possible?
What I want to do is something like this (but the code below does not work):
function Something(){
// init stuff
}
function createSomething(){
return new Something.apply(null, arguments);
}
var s = createSomething(a,b,c); // 's' is an instance of Something
The Answer
From the responses here, it became clear that there's no built-in way to call .apply() with the new operator. However, people suggested a number of really interesting solutions to the problem.
My preferred solution was this one from Matthew Crumley (I've modified it to pass the arguments property):
var createSomething = (function() {
function F(args) {
return Something.apply(this, args);
}
F.prototype = Something.prototype;
return function() {
return new F(arguments);
}
})();

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.

Here's a generalized solution that can call any constructor (except native constructors that behave differently when called as functions, like String, Number, Date, etc.) with an array of arguments:
function construct(constructor, args) {
function F() {
return constructor.apply(this, args);
}
F.prototype = constructor.prototype;
return new F();
}
An object created by calling construct(Class, [1, 2, 3]) would be identical to an object created with new Class(1, 2, 3).
You could also make a more specific version so you don't have to pass the constructor every time. This is also slightly more efficient, since it doesn't need to create a new instance of the inner function every time you call it.
var createSomething = (function() {
function F(args) {
return Something.apply(this, args);
}
F.prototype = Something.prototype;
return function(args) {
return new F(args);
}
})();
The reason for creating and calling the outer anonymous function like that is to keep function F from polluting the global namespace. It's sometimes called the module pattern.
[UPDATE]
For those who want to use this in TypeScript, since TS gives an error if F returns anything:
function construct(constructor, args) {
function F() : void {
constructor.apply(this, args);
}
F.prototype = constructor.prototype;
return new F();
}

If your environment supports ECMA Script 2015's spread operator (...), you can simply use it like this
function Something() {
// init stuff
}
function createSomething() {
return new Something(...arguments);
}
Note: Now that the ECMA Script 2015's specifications are published and most JavaScript engines are actively implementing it, this would be the preferred way of doing this.
You can check the Spread operator's support in few of the major environments, here.

Suppose you've got an Items constructor which slurps up all the arguments you throw at it:
function Items () {
this.elems = [].slice.call(arguments);
}
Items.prototype.sum = function () {
return this.elems.reduce(function (sum, x) { return sum + x }, 0);
};
You can create an instance with Object.create() and then .apply() with that instance:
var items = Object.create(Items.prototype);
Items.apply(items, [ 1, 2, 3, 4 ]);
console.log(items.sum());
Which when run prints 10 since 1 + 2 + 3 + 4 == 10:
$ node t.js
10

In ES6, Reflect.construct() is quite convenient:
Reflect.construct(F, args)

#Matthew
I think it's better to fix the constructor property also.
// Invoke new operator with arbitrary arguments
// Holy Grail pattern
function invoke(constructor, args) {
var f;
function F() {
// constructor returns **this**
return constructor.apply(this, args);
}
F.prototype = constructor.prototype;
f = new F();
f.constructor = constructor;
return f;
}

You could move the init stuff out into a separate method of Something's prototype:
function Something() {
// Do nothing
}
Something.prototype.init = function() {
// Do init stuff
};
function createSomething() {
var s = new Something();
s.init.apply(s, arguments);
return s;
}
var s = createSomething(a,b,c); // 's' is an instance of Something

An improved version of #Matthew's answer. This form has the slight performance benefits obtained by storing the temp class in a closure, as well as the flexibility of having one function able to be used to create any class
var applyCtor = function(){
var tempCtor = function() {};
return function(ctor, args){
tempCtor.prototype = ctor.prototype;
var instance = new tempCtor();
ctor.prototype.constructor.apply(instance,args);
return instance;
}
}();
This would be used by calling applyCtor(class, [arg1, arg2, argn]);

This answer is a little late, but figured anyone who sees this might be able to use it. There is a way to return a new object using apply. Though it requires one little change to your object declaration.
function testNew() {
if (!( this instanceof arguments.callee ))
return arguments.callee.apply( new arguments.callee(), arguments );
this.arg = Array.prototype.slice.call( arguments );
return this;
}
testNew.prototype.addThem = function() {
var newVal = 0,
i = 0;
for ( ; i < this.arg.length; i++ ) {
newVal += this.arg[i];
}
return newVal;
}
testNew( 4, 8 ) === { arg : [ 4, 8 ] };
testNew( 1, 2, 3, 4, 5 ).addThem() === 15;
For the first if statement to work in testNew you have to return this; at the bottom of the function. So as an example with your code:
function Something() {
// init stuff
return this;
}
function createSomething() {
return Something.apply( new Something(), arguments );
}
var s = createSomething( a, b, c );
Update: I've changed my first example to sum any number of arguments, instead of just two.

I just came across this problem, and I solved it like this:
function instantiate(ctor) {
switch (arguments.length) {
case 1: return new ctor();
case 2: return new ctor(arguments[1]);
case 3: return new ctor(arguments[1], arguments[2]);
case 4: return new ctor(arguments[1], arguments[2], arguments[3]);
//...
default: throw new Error('instantiate: too many parameters');
}
}
function Thing(a, b, c) {
console.log(a);
console.log(b);
console.log(c);
}
var thing = instantiate(Thing, 'abc', 123, {x:5});
Yeah, it's a bit ugly, but it solves the problem, and it's dead simple.

if you're interested in an eval-based solution
function createSomething() {
var q = [];
for(var i = 0; i < arguments.length; i++)
q.push("arguments[" + i + "]");
return eval("new Something(" + q.join(",") + ")");
}

This works!
var cls = Array; //eval('Array'); dynamically
var data = [2];
new cls(...data);

See also how CoffeeScript does it.
s = new Something([a,b,c]...)
becomes:
var s;
s = (function(func, args, ctor) {
ctor.prototype = func.prototype;
var child = new ctor, result = func.apply(child, args);
return Object(result) === result ? result : child;
})(Something, [a, b, c], function(){});

This constructor approach works both with and without the new keyword:
function Something(foo, bar){
if (!(this instanceof Something)){
var obj = Object.create(Something.prototype);
return Something.apply(obj, arguments);
}
this.foo = foo;
this.bar = bar;
return this;
}
It assumes support for Object.create but you could always polyfill that if you're supporting older browsers. See the support table on MDN here.
Here's a JSBin to see it in action with console output.

Solution without ES6 or polyfills:
var obj = _new(Demo).apply(["X", "Y", "Z"]);
function _new(constr)
{
function createNamedFunction(name)
{
return (new Function("return function " + name + "() { };"))();
}
var func = createNamedFunction(constr.name);
func.prototype = constr.prototype;
var self = new func();
return { apply: function(args) {
constr.apply(self, args);
return self;
} };
}
function Demo()
{
for(var index in arguments)
{
this['arg' + (parseInt(index) + 1)] = arguments[index];
}
}
Demo.prototype.tagged = true;
console.log(obj);
console.log(obj.tagged);
output
Demo {arg1: "X", arg2: "Y", arg3: "Z"}
... or "shorter" way:
var func = new Function("return function " + Demo.name + "() { };")();
func.prototype = Demo.prototype;
var obj = new func();
Demo.apply(obj, ["X", "Y", "Z"]);
edit:
I think this might be a good solution:
this.forConstructor = function(constr)
{
return { apply: function(args)
{
let name = constr.name.replace('-', '_');
let func = (new Function('args', name + '_', " return function " + name + "() { " + name + "_.apply(this, args); }"))(args, constr);
func.constructor = constr;
func.prototype = constr.prototype;
return new func(args);
}};
}

You can't call a constructor with a variable number of arguments like you want with the new operator.
What you can do is change the constructor slightly. Instead of:
function Something() {
// deal with the "arguments" array
}
var obj = new Something.apply(null, [0, 0]); // doesn't work!
Do this instead:
function Something(args) {
// shorter, but will substitute a default if args.x is 0, false, "" etc.
this.x = args.x || SOME_DEFAULT_VALUE;
// longer, but will only put in a default if args.x is not supplied
this.x = (args.x !== undefined) ? args.x : SOME_DEFAULT_VALUE;
}
var obj = new Something({x: 0, y: 0});
Or if you must use an array:
function Something(args) {
var x = args[0];
var y = args[1];
}
var obj = new Something([0, 0]);

Matthew Crumley's solutions in CoffeeScript:
construct = (constructor, args) ->
F = -> constructor.apply this, args
F.prototype = constructor.prototype
new F
or
createSomething = (->
F = (args) -> Something.apply this, args
F.prototype = Something.prototype
return -> new Something arguments
)()

function createSomething() {
var args = Array.prototype.concat.apply([null], arguments);
return new (Function.prototype.bind.apply(Something, args));
}
If your target browser doesn't support ECMAScript 5 Function.prototype.bind, the code won't work. It is not very likely though, see compatibilty table.

modified #Matthew answer. Here I can pass any number of parameters to function as usual (not array). Also 'Something' is not hardcoded into:
function createObject( constr ) {
var args = arguments;
var wrapper = function() {
return constr.apply( this, Array.prototype.slice.call(args, 1) );
}
wrapper.prototype = constr.prototype;
return new wrapper();
}
function Something() {
// init stuff
};
var obj1 = createObject( Something, 1, 2, 3 );
var same = new Something( 1, 2, 3 );

This one-liner should do it:
new (Function.prototype.bind.apply(Something, [null].concat(arguments)));

While the other approaches are workable, they're unduly complex. In Clojure you generally create a function that instantiates types/records and use that function as the mechanism for instantiation. Translating this to JavaScript:
function Person(surname, name){
this.surname = surname;
this.name = name;
}
function person(surname, name){
return new Person(surname, name);
}
By taking this approach you avoid the use of new except as described above. And this function, of course, has no issues working with apply or any number of other functional programming features.
var doe = _.partial(person, "Doe");
var john = doe("John");
var jane = doe("Jane");
By using this approach, all of your type constructors (e.g. Person) are vanilla, do-nothing constructors. You just pass in arguments and assign them to properties of the same name. The hairy details go in the constructor function (e.g. person).
It is of little bother having to create these extra constructor functions since they are a good practice anyhow. They can be convenient since they allow you to potentially have several constructor functions with different nuances.

It's also intresting to see how the issue of reusing the temporary F() constructor, was addressed by using arguments.callee, aka the creator/factory function itself:
http://www.dhtmlkitchen.com/?category=/JavaScript/&date=2008/05/11/&entry=Decorator-Factory-Aspect

Any function (even a constructor) can take a variable number of arguments. Each function has an "arguments" variable which can be cast to an array with [].slice.call(arguments).
function Something(){
this.options = [].slice.call(arguments);
this.toString = function (){
return this.options.toString();
};
}
var s = new Something(1, 2, 3, 4);
console.log( 's.options === "1,2,3,4":', (s.options == '1,2,3,4') );
var z = new Something(9, 10, 11);
console.log( 'z.options === "9,10,11":', (z.options == '9,10,11') );
The above tests produce the following output:
s.options === "1,2,3,4": true
z.options === "9,10,11": true

Here is my version of createSomething:
function createSomething() {
var obj = {};
obj = Something.apply(obj, arguments) || obj;
obj.__proto__ = Something.prototype; //Object.setPrototypeOf(obj, Something.prototype);
return o;
}
Based on that, I tried to simulate the new keyword of JavaScript:
//JavaScript 'new' keyword simulation
function new2() {
var obj = {}, args = Array.prototype.slice.call(arguments), fn = args.shift();
obj = fn.apply(obj, args) || obj;
Object.setPrototypeOf(obj, fn.prototype); //or: obj.__proto__ = fn.prototype;
return obj;
}
I tested it and it seems that it works perfectly fine for all scenarios. It also works on native constructors like Date. Here are some tests:
//test
new2(Something);
new2(Something, 1, 2);
new2(Date); //"Tue May 13 2014 01:01:09 GMT-0700" == new Date()
new2(Array); //[] == new Array()
new2(Array, 3); //[undefined × 3] == new Array(3)
new2(Object); //Object {} == new Object()
new2(Object, 2); //Number {} == new Object(2)
new2(Object, "s"); //String {0: "s", length: 1} == new Object("s")
new2(Object, true); //Boolean {} == new Object(true)

Yes we can, javascript is more of prototype inheritance in nature.
function Actor(name, age){
this.name = name;
this.age = age;
}
Actor.prototype.name = "unknown";
Actor.prototype.age = "unknown";
Actor.prototype.getName = function() {
return this.name;
};
Actor.prototype.getAge = function() {
return this.age;
};
when we create an object with "new" then our created object INHERITS getAge(), But if we used apply(...) or call(...) to call Actor, then we are passing an object for "this" but the object we pass WON'T inherit from Actor.prototype
unless, we directly pass apply or call Actor.prototype but then.... "this" would point to "Actor.prototype" and this.name would write to: Actor.prototype.name. Thus affecting all other objects created with Actor...since we overwrite the prototype rather than the instance
var rajini = new Actor('Rajinikanth', 31);
console.log(rajini);
console.log(rajini.getName());
console.log(rajini.getAge());
var kamal = new Actor('kamal', 18);
console.log(kamal);
console.log(kamal.getName());
console.log(kamal.getAge());
Let's try with apply
var vijay = Actor.apply(null, ["pandaram", 33]);
if (vijay === undefined) {
console.log("Actor(....) didn't return anything
since we didn't call it with new");
}
var ajith = {};
Actor.apply(ajith, ['ajith', 25]);
console.log(ajith); //Object {name: "ajith", age: 25}
try {
ajith.getName();
} catch (E) {
console.log("Error since we didn't inherit ajith.prototype");
}
console.log(Actor.prototype.age); //Unknown
console.log(Actor.prototype.name); //Unknown
By passing Actor.prototype to Actor.call() as the first argument, when the Actor() function is ran, it executes this.name=name, Since "this" will point to Actor.prototype, this.name=name; means Actor.prototype.name=name;
var simbhu = Actor.apply(Actor.prototype, ['simbhu', 28]);
if (simbhu === undefined) {
console.log("Still undefined since the function didn't return anything.");
}
console.log(Actor.prototype.age); //simbhu
console.log(Actor.prototype.name); //28
var copy = Actor.prototype;
var dhanush = Actor.apply(copy, ["dhanush", 11]);
console.log(dhanush);
console.log("But now we've corrupted Parent.prototype in order to inherit");
console.log(Actor.prototype.age); //11
console.log(Actor.prototype.name); //dhanush
Coming back to orginal question how to use new operator with apply, here is my take....
Function.prototype.new = function(){
var constructor = this;
function fn() {return constructor.apply(this, args)}
var args = Array.prototype.slice.call(arguments);
fn.prototype = this.prototype;
return new fn
};
var thalaivar = Actor.new.apply(Parent, ["Thalaivar", 30]);
console.log(thalaivar);

since ES6 this is possible through the Spread operator, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator#Apply_for_new
This answer was already, sort of given in comment https://stackoverflow.com/a/42027742/7049810, but seems to have been missed by most

Actually the simplest method is:
function Something (a, b) {
this.a = a;
this.b = b;
}
function createSomething(){
return Something;
}
s = new (createSomething())(1, 2);
// s == Something {a: 1, b: 2}

A revised solution from #jordancpaul's answer.
var applyCtor = function(ctor, args)
{
var instance = new ctor();
ctor.prototype.constructor.apply(instance, args);
return instance;
};

Make an anonymous prototype and apply the Something prototype to it using the arguments and then create a new instance of that anonymous prototype. The one disadavantage of this is it will not pass the s instanceof Something check, though it is identical, it is basically an instance of a clone.
function Something(){
// init stuff
}
function createSomething(){
return new (function(){Something.apply(this, arguments)});
}
var s = createSomething(a,b,c); // 's' is an instance of Something

function FooFactory() {
var prototype, F = function(){};
function Foo() {
var args = Array.prototype.slice.call(arguments),
i;
for (i = 0, this.args = {}; i < args.length; i +=1) {
this.args[i] = args[i];
}
this.bar = 'baz';
this.print();
return this;
}
prototype = Foo.prototype;
prototype.print = function () {
console.log(this.bar);
};
F.prototype = prototype;
return Foo.apply(new F(), Array.prototype.slice.call(arguments));
}
var foo = FooFactory('a', 'b', 'c', 'd', {}, function (){});
console.log('foo:',foo);
foo.print();

Related

How to create an object without calling constructor function and new keyword [duplicate]

In JavaScript, I want to create an object instance (via the new operator), but pass an arbitrary number of arguments to the constructor. Is this possible?
What I want to do is something like this (but the code below does not work):
function Something(){
// init stuff
}
function createSomething(){
return new Something.apply(null, arguments);
}
var s = createSomething(a,b,c); // 's' is an instance of Something
The Answer
From the responses here, it became clear that there's no built-in way to call .apply() with the new operator. However, people suggested a number of really interesting solutions to the problem.
My preferred solution was this one from Matthew Crumley (I've modified it to pass the arguments property):
var createSomething = (function() {
function F(args) {
return Something.apply(this, args);
}
F.prototype = Something.prototype;
return function() {
return new F(arguments);
}
})();
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.
Here's a generalized solution that can call any constructor (except native constructors that behave differently when called as functions, like String, Number, Date, etc.) with an array of arguments:
function construct(constructor, args) {
function F() {
return constructor.apply(this, args);
}
F.prototype = constructor.prototype;
return new F();
}
An object created by calling construct(Class, [1, 2, 3]) would be identical to an object created with new Class(1, 2, 3).
You could also make a more specific version so you don't have to pass the constructor every time. This is also slightly more efficient, since it doesn't need to create a new instance of the inner function every time you call it.
var createSomething = (function() {
function F(args) {
return Something.apply(this, args);
}
F.prototype = Something.prototype;
return function(args) {
return new F(args);
}
})();
The reason for creating and calling the outer anonymous function like that is to keep function F from polluting the global namespace. It's sometimes called the module pattern.
[UPDATE]
For those who want to use this in TypeScript, since TS gives an error if F returns anything:
function construct(constructor, args) {
function F() : void {
constructor.apply(this, args);
}
F.prototype = constructor.prototype;
return new F();
}
If your environment supports ECMA Script 2015's spread operator (...), you can simply use it like this
function Something() {
// init stuff
}
function createSomething() {
return new Something(...arguments);
}
Note: Now that the ECMA Script 2015's specifications are published and most JavaScript engines are actively implementing it, this would be the preferred way of doing this.
You can check the Spread operator's support in few of the major environments, here.
Suppose you've got an Items constructor which slurps up all the arguments you throw at it:
function Items () {
this.elems = [].slice.call(arguments);
}
Items.prototype.sum = function () {
return this.elems.reduce(function (sum, x) { return sum + x }, 0);
};
You can create an instance with Object.create() and then .apply() with that instance:
var items = Object.create(Items.prototype);
Items.apply(items, [ 1, 2, 3, 4 ]);
console.log(items.sum());
Which when run prints 10 since 1 + 2 + 3 + 4 == 10:
$ node t.js
10
In ES6, Reflect.construct() is quite convenient:
Reflect.construct(F, args)
#Matthew
I think it's better to fix the constructor property also.
// Invoke new operator with arbitrary arguments
// Holy Grail pattern
function invoke(constructor, args) {
var f;
function F() {
// constructor returns **this**
return constructor.apply(this, args);
}
F.prototype = constructor.prototype;
f = new F();
f.constructor = constructor;
return f;
}
You could move the init stuff out into a separate method of Something's prototype:
function Something() {
// Do nothing
}
Something.prototype.init = function() {
// Do init stuff
};
function createSomething() {
var s = new Something();
s.init.apply(s, arguments);
return s;
}
var s = createSomething(a,b,c); // 's' is an instance of Something
An improved version of #Matthew's answer. This form has the slight performance benefits obtained by storing the temp class in a closure, as well as the flexibility of having one function able to be used to create any class
var applyCtor = function(){
var tempCtor = function() {};
return function(ctor, args){
tempCtor.prototype = ctor.prototype;
var instance = new tempCtor();
ctor.prototype.constructor.apply(instance,args);
return instance;
}
}();
This would be used by calling applyCtor(class, [arg1, arg2, argn]);
This answer is a little late, but figured anyone who sees this might be able to use it. There is a way to return a new object using apply. Though it requires one little change to your object declaration.
function testNew() {
if (!( this instanceof arguments.callee ))
return arguments.callee.apply( new arguments.callee(), arguments );
this.arg = Array.prototype.slice.call( arguments );
return this;
}
testNew.prototype.addThem = function() {
var newVal = 0,
i = 0;
for ( ; i < this.arg.length; i++ ) {
newVal += this.arg[i];
}
return newVal;
}
testNew( 4, 8 ) === { arg : [ 4, 8 ] };
testNew( 1, 2, 3, 4, 5 ).addThem() === 15;
For the first if statement to work in testNew you have to return this; at the bottom of the function. So as an example with your code:
function Something() {
// init stuff
return this;
}
function createSomething() {
return Something.apply( new Something(), arguments );
}
var s = createSomething( a, b, c );
Update: I've changed my first example to sum any number of arguments, instead of just two.
I just came across this problem, and I solved it like this:
function instantiate(ctor) {
switch (arguments.length) {
case 1: return new ctor();
case 2: return new ctor(arguments[1]);
case 3: return new ctor(arguments[1], arguments[2]);
case 4: return new ctor(arguments[1], arguments[2], arguments[3]);
//...
default: throw new Error('instantiate: too many parameters');
}
}
function Thing(a, b, c) {
console.log(a);
console.log(b);
console.log(c);
}
var thing = instantiate(Thing, 'abc', 123, {x:5});
Yeah, it's a bit ugly, but it solves the problem, and it's dead simple.
if you're interested in an eval-based solution
function createSomething() {
var q = [];
for(var i = 0; i < arguments.length; i++)
q.push("arguments[" + i + "]");
return eval("new Something(" + q.join(",") + ")");
}
This works!
var cls = Array; //eval('Array'); dynamically
var data = [2];
new cls(...data);
See also how CoffeeScript does it.
s = new Something([a,b,c]...)
becomes:
var s;
s = (function(func, args, ctor) {
ctor.prototype = func.prototype;
var child = new ctor, result = func.apply(child, args);
return Object(result) === result ? result : child;
})(Something, [a, b, c], function(){});
This constructor approach works both with and without the new keyword:
function Something(foo, bar){
if (!(this instanceof Something)){
var obj = Object.create(Something.prototype);
return Something.apply(obj, arguments);
}
this.foo = foo;
this.bar = bar;
return this;
}
It assumes support for Object.create but you could always polyfill that if you're supporting older browsers. See the support table on MDN here.
Here's a JSBin to see it in action with console output.
Solution without ES6 or polyfills:
var obj = _new(Demo).apply(["X", "Y", "Z"]);
function _new(constr)
{
function createNamedFunction(name)
{
return (new Function("return function " + name + "() { };"))();
}
var func = createNamedFunction(constr.name);
func.prototype = constr.prototype;
var self = new func();
return { apply: function(args) {
constr.apply(self, args);
return self;
} };
}
function Demo()
{
for(var index in arguments)
{
this['arg' + (parseInt(index) + 1)] = arguments[index];
}
}
Demo.prototype.tagged = true;
console.log(obj);
console.log(obj.tagged);
output
Demo {arg1: "X", arg2: "Y", arg3: "Z"}
... or "shorter" way:
var func = new Function("return function " + Demo.name + "() { };")();
func.prototype = Demo.prototype;
var obj = new func();
Demo.apply(obj, ["X", "Y", "Z"]);
edit:
I think this might be a good solution:
this.forConstructor = function(constr)
{
return { apply: function(args)
{
let name = constr.name.replace('-', '_');
let func = (new Function('args', name + '_', " return function " + name + "() { " + name + "_.apply(this, args); }"))(args, constr);
func.constructor = constr;
func.prototype = constr.prototype;
return new func(args);
}};
}
You can't call a constructor with a variable number of arguments like you want with the new operator.
What you can do is change the constructor slightly. Instead of:
function Something() {
// deal with the "arguments" array
}
var obj = new Something.apply(null, [0, 0]); // doesn't work!
Do this instead:
function Something(args) {
// shorter, but will substitute a default if args.x is 0, false, "" etc.
this.x = args.x || SOME_DEFAULT_VALUE;
// longer, but will only put in a default if args.x is not supplied
this.x = (args.x !== undefined) ? args.x : SOME_DEFAULT_VALUE;
}
var obj = new Something({x: 0, y: 0});
Or if you must use an array:
function Something(args) {
var x = args[0];
var y = args[1];
}
var obj = new Something([0, 0]);
Matthew Crumley's solutions in CoffeeScript:
construct = (constructor, args) ->
F = -> constructor.apply this, args
F.prototype = constructor.prototype
new F
or
createSomething = (->
F = (args) -> Something.apply this, args
F.prototype = Something.prototype
return -> new Something arguments
)()
function createSomething() {
var args = Array.prototype.concat.apply([null], arguments);
return new (Function.prototype.bind.apply(Something, args));
}
If your target browser doesn't support ECMAScript 5 Function.prototype.bind, the code won't work. It is not very likely though, see compatibilty table.
modified #Matthew answer. Here I can pass any number of parameters to function as usual (not array). Also 'Something' is not hardcoded into:
function createObject( constr ) {
var args = arguments;
var wrapper = function() {
return constr.apply( this, Array.prototype.slice.call(args, 1) );
}
wrapper.prototype = constr.prototype;
return new wrapper();
}
function Something() {
// init stuff
};
var obj1 = createObject( Something, 1, 2, 3 );
var same = new Something( 1, 2, 3 );
This one-liner should do it:
new (Function.prototype.bind.apply(Something, [null].concat(arguments)));
While the other approaches are workable, they're unduly complex. In Clojure you generally create a function that instantiates types/records and use that function as the mechanism for instantiation. Translating this to JavaScript:
function Person(surname, name){
this.surname = surname;
this.name = name;
}
function person(surname, name){
return new Person(surname, name);
}
By taking this approach you avoid the use of new except as described above. And this function, of course, has no issues working with apply or any number of other functional programming features.
var doe = _.partial(person, "Doe");
var john = doe("John");
var jane = doe("Jane");
By using this approach, all of your type constructors (e.g. Person) are vanilla, do-nothing constructors. You just pass in arguments and assign them to properties of the same name. The hairy details go in the constructor function (e.g. person).
It is of little bother having to create these extra constructor functions since they are a good practice anyhow. They can be convenient since they allow you to potentially have several constructor functions with different nuances.
It's also intresting to see how the issue of reusing the temporary F() constructor, was addressed by using arguments.callee, aka the creator/factory function itself:
http://www.dhtmlkitchen.com/?category=/JavaScript/&date=2008/05/11/&entry=Decorator-Factory-Aspect
Any function (even a constructor) can take a variable number of arguments. Each function has an "arguments" variable which can be cast to an array with [].slice.call(arguments).
function Something(){
this.options = [].slice.call(arguments);
this.toString = function (){
return this.options.toString();
};
}
var s = new Something(1, 2, 3, 4);
console.log( 's.options === "1,2,3,4":', (s.options == '1,2,3,4') );
var z = new Something(9, 10, 11);
console.log( 'z.options === "9,10,11":', (z.options == '9,10,11') );
The above tests produce the following output:
s.options === "1,2,3,4": true
z.options === "9,10,11": true
Here is my version of createSomething:
function createSomething() {
var obj = {};
obj = Something.apply(obj, arguments) || obj;
obj.__proto__ = Something.prototype; //Object.setPrototypeOf(obj, Something.prototype);
return o;
}
Based on that, I tried to simulate the new keyword of JavaScript:
//JavaScript 'new' keyword simulation
function new2() {
var obj = {}, args = Array.prototype.slice.call(arguments), fn = args.shift();
obj = fn.apply(obj, args) || obj;
Object.setPrototypeOf(obj, fn.prototype); //or: obj.__proto__ = fn.prototype;
return obj;
}
I tested it and it seems that it works perfectly fine for all scenarios. It also works on native constructors like Date. Here are some tests:
//test
new2(Something);
new2(Something, 1, 2);
new2(Date); //"Tue May 13 2014 01:01:09 GMT-0700" == new Date()
new2(Array); //[] == new Array()
new2(Array, 3); //[undefined × 3] == new Array(3)
new2(Object); //Object {} == new Object()
new2(Object, 2); //Number {} == new Object(2)
new2(Object, "s"); //String {0: "s", length: 1} == new Object("s")
new2(Object, true); //Boolean {} == new Object(true)
Yes we can, javascript is more of prototype inheritance in nature.
function Actor(name, age){
this.name = name;
this.age = age;
}
Actor.prototype.name = "unknown";
Actor.prototype.age = "unknown";
Actor.prototype.getName = function() {
return this.name;
};
Actor.prototype.getAge = function() {
return this.age;
};
when we create an object with "new" then our created object INHERITS getAge(), But if we used apply(...) or call(...) to call Actor, then we are passing an object for "this" but the object we pass WON'T inherit from Actor.prototype
unless, we directly pass apply or call Actor.prototype but then.... "this" would point to "Actor.prototype" and this.name would write to: Actor.prototype.name. Thus affecting all other objects created with Actor...since we overwrite the prototype rather than the instance
var rajini = new Actor('Rajinikanth', 31);
console.log(rajini);
console.log(rajini.getName());
console.log(rajini.getAge());
var kamal = new Actor('kamal', 18);
console.log(kamal);
console.log(kamal.getName());
console.log(kamal.getAge());
Let's try with apply
var vijay = Actor.apply(null, ["pandaram", 33]);
if (vijay === undefined) {
console.log("Actor(....) didn't return anything
since we didn't call it with new");
}
var ajith = {};
Actor.apply(ajith, ['ajith', 25]);
console.log(ajith); //Object {name: "ajith", age: 25}
try {
ajith.getName();
} catch (E) {
console.log("Error since we didn't inherit ajith.prototype");
}
console.log(Actor.prototype.age); //Unknown
console.log(Actor.prototype.name); //Unknown
By passing Actor.prototype to Actor.call() as the first argument, when the Actor() function is ran, it executes this.name=name, Since "this" will point to Actor.prototype, this.name=name; means Actor.prototype.name=name;
var simbhu = Actor.apply(Actor.prototype, ['simbhu', 28]);
if (simbhu === undefined) {
console.log("Still undefined since the function didn't return anything.");
}
console.log(Actor.prototype.age); //simbhu
console.log(Actor.prototype.name); //28
var copy = Actor.prototype;
var dhanush = Actor.apply(copy, ["dhanush", 11]);
console.log(dhanush);
console.log("But now we've corrupted Parent.prototype in order to inherit");
console.log(Actor.prototype.age); //11
console.log(Actor.prototype.name); //dhanush
Coming back to orginal question how to use new operator with apply, here is my take....
Function.prototype.new = function(){
var constructor = this;
function fn() {return constructor.apply(this, args)}
var args = Array.prototype.slice.call(arguments);
fn.prototype = this.prototype;
return new fn
};
var thalaivar = Actor.new.apply(Parent, ["Thalaivar", 30]);
console.log(thalaivar);
since ES6 this is possible through the Spread operator, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator#Apply_for_new
This answer was already, sort of given in comment https://stackoverflow.com/a/42027742/7049810, but seems to have been missed by most
Actually the simplest method is:
function Something (a, b) {
this.a = a;
this.b = b;
}
function createSomething(){
return Something;
}
s = new (createSomething())(1, 2);
// s == Something {a: 1, b: 2}
A revised solution from #jordancpaul's answer.
var applyCtor = function(ctor, args)
{
var instance = new ctor();
ctor.prototype.constructor.apply(instance, args);
return instance;
};
Make an anonymous prototype and apply the Something prototype to it using the arguments and then create a new instance of that anonymous prototype. The one disadavantage of this is it will not pass the s instanceof Something check, though it is identical, it is basically an instance of a clone.
function Something(){
// init stuff
}
function createSomething(){
return new (function(){Something.apply(this, arguments)});
}
var s = createSomething(a,b,c); // 's' is an instance of Something
function FooFactory() {
var prototype, F = function(){};
function Foo() {
var args = Array.prototype.slice.call(arguments),
i;
for (i = 0, this.args = {}; i < args.length; i +=1) {
this.args[i] = args[i];
}
this.bar = 'baz';
this.print();
return this;
}
prototype = Foo.prototype;
prototype.print = function () {
console.log(this.bar);
};
F.prototype = prototype;
return Foo.apply(new F(), Array.prototype.slice.call(arguments));
}
var foo = FooFactory('a', 'b', 'c', 'd', {}, function (){});
console.log('foo:',foo);
foo.print();

How can create own call function in javascript?

As of my knowledge, in javascript there are three concepts; call, apply and bind
I want to create these function with similar behavior.
Here is a polyfill for them (not accurate though, just what came into my mind):
Function.prototype.call = function(context, ...args) {
const fn = Symbol();
try {
context[fn] = this;
return context[fn](...args);
} catch(e) {
// Turn primitive types into complex ones 1 -> Number, thanks to Mark Meyer for this.
context = new context.constructor(context);
context[fn] = this;
}
return context[fn](...args);
};
Function.prototype.apply = function(context, args) {
return this.call(context, ...args);
};
Function.prototype.bind = function(context, ...args) {
return (...args2) => this.call(context, ...args, ...args2);
};
The only thing that is impossible to polyfill is fn.call(null), as that primitive can't be turned into a complex type, only native code can do this
Add your own call function like "_call"
Function.prototype._call = function(newcontext, ...arg){
var demoFn = new Function('tempfuncton', 'tempthis','arg' , '{ tempthis["f"]=tempfuncton; return tempthis.f(arg);}');
demoFn(this,newcontext,arg);
}
write a demo function
function anyfunction(args){
console.log(this,args)
}
call it like previous. First argument should be an object. Otherwise write a code to convert it into object.
anyfunction._call({'mm':'my provided this object'},"arg1","arg2")
function B(a,b,c){
console.log(a,b,c)
}
Function.prototype.OwnCallFunction = function(){
if( this.length == arguments.length)
this(...arguments)
else
console.error('Signature does not match')
}
B.OwnCallFunction(323,34,34)
I followed this approach to create own call function. With help of Function
Constructor, I add a function to it and it worked on firefox.
New approach, with more clarity
Function.prototype.call2 = function(context, ...args){
console.log(context)
const fn = Symbol();
context[fn] = this;
context[fn](...args);
}
In above answers I can see that spread operators has been used, but if we really want to make pollyfill of call then we should avoid spread
operator and latest concept of es6.I am sharing solution without es6.
Call Function:-
Function.prototype.myCall = function(obj) {
obj = obj || global;
var id = "00" + Math.random();
while (obj.hasOwnProperty(id)) {
id = "00" + Math.random();
}
obj[id] = this;
let arg=[];
for(let i=1;i<arguments.length;i++){
arg.push("arguments[" + i + "]");
}
result= eval("obj[id]("+arg+")");
delete obj[id];
return result;
}
Apply function:-
Function.prototype.myApply = function(obj, argArr) {
obj = obj || global;
var id = "00" + Math.random();
while (obj.hasOwnProperty(id)) {
id = "00" + Math.random();
}
obj[id] = this;
let arg=[];
let result
if(!argArr){
result= obj[id].fn();
}
else{
for(let i=0;i<argArr.length;i++){
arg.push("argArr[" + i + "]");
}
result= eval("obj[id]("+arg+")");
delete obj[id];
}
return result;
}
Bind function:-
Function.prototype.myBind2= function(){
let obj1= this;
const obj= Array.prototype.slice.call(arguments,0,1);
const arg= Array.prototype.slice.call(arguments,1);
return function(){
const arg2= Array.prototype.slice.call(arguments);
obj1.apply(obj[0],Array.prototype.concat(arg, arg2));
}
Another solution Bind: we can pass object argument of function
Function.prototype.myBind2 = function(obj) {
let fn = this;
const arg = Array.prototype.slice.call(arguments, 1);
return function() {
const arg2 = Array.prototype.slice.call(arguments);
fn.apply(obj, Array.prototype.concat(arg, arg2));
}
While each browser has its own source code for implementing Javascript, you can find how many of the native Javascript functions are implemented with the ECMA specifications found here:
http://www.ecma-international.org/ecma-262/10.0/index.html#sec-properties-of-the-function-prototype-object
For specs of apply, see: 19.2.3.1
For specs of bind, see: 19.2.3.2
For specs of call, see: 19.2.3.3
If you're interested for example, how Node implemented apply, you can dig into their source code on Github here: https://github.com/nodejs/node
Here is my sweet and simple solution. We are adding the ObjRef in prototypal chain to avoid any name conflicts with other properties
Function.prototype.call2 = function (objRef, ...args) {
otherObj = Object.create(objRef)
otherObj[this.name] = this;
otherObj[this.name](...args);
}
I don't think using Object.create makes sense here as when you will console this inside the function you won't see the desired object.
Here is my try(not accurate though) but will work.
Function.prototype.myCall = function (thisContext, ...param) {
let name = this.name;
thisContext[name] = this;
thisContext[name](...param);
}
Function.prototype.mycall = function(context, ...args){
context.fun= this; //add personal function to context
context.fun(...args);
}
function personal (msg){
alert(this.name + " " + msg);
}
let obj = {
name:'Ajinkya'
}
personal.mycall(obj,'Khandar'); // pass object and args in mycall

how to implement parasitic inheritance to avoid nesting

I would like to follow the inheritance structure shown above. I would like create an engineer using this syntax:
var Mark = new Employee(id).WorkerBee(project).Engineer();
To achieve this syntax, I have to create a nested object following a parasitic inheritance pattern like so:
function Employee(id) {
this.id = id;
this.WorkerBee = function(project) {
this.project = project;
this.Engineer = function() {
...
return this;
};
return this;
};
}
To avoid deep layers of nesting, I am trying to rewrite it using prototypes. How can I rewrite my code to achieve the same goal as above ?
function Employee(id) {
//variables
this.id = id
this.name = "";
this.dept = "general";
//methods
this.getId = function() {
return this.id
}
}
Employee.prototype.WorkerBee = WorkerBee;
function WorkerBee(project) {
//variables
this.projectName = project
this.projects = [];
//methods
this.getProjectName = function() {
return this.projectName
}
return this
}
WorkerBee.prototype.Engineer = Engineer
function Engineer() {
//variables
this.dept = "engineering";
this.machine = "";
//methods
this.getDept = function() {
return this.dept
}
return this
}
var Mark = new Employee("5").WorkerBee("Secret Project").Engineer();
console.log(Mark.getId()) //should print "5"
console.log(Mark.getProjectName()) //should print "Secret Project"
console.log(Mark.getDept()) //should print engineering
UPDATE:
Ok, I understand partially. What is the reason why you want to do this? Do you just want a shortcut for creating multiple instances using multiple statements?
Should the instance of C returned by A().B().C() be any different than the one created with the standard new C()?
If you just want to chain constructors, you can add the context in which they are defined (most likely the global object) to the prototype chain of the created entities. You should be able to do that:
var A = function () {};
A.prototype = Object.create(this);
What this does not eliminate though is the need for the new keyword for instantiation. You would need to do new (new (new A()).B()).C(). I can't think of a different approach than having a helper function which would create constructors which do not require the new keyword:
var define = function (init) {
var Constructor = function () {
if (!(this instanceof Constructor)) {
return new Constructor();
}
if (init) {
init.apply(this, Array.prototype.slice.call(arguments));
}
};
Constructor.prototype = Object.create(this);
return Constructor;
};
The usage is:
var A = define(function (x, y) {
this.x = x;
this.y = y;
});
var a1 = new A(1, 2);
// a1 instanceof A === true
// a1.x === 1
// a1.y === 2
var a2 = A(1, 2);
// a2 instanceof A === true
// a2.x === 1
// a2.y === 2
If you have the constructors A, B and C, you can use the following notations interchangeably:
var a = new A();
var b = new B();
var c = new C();
var a = A();
var b = B();
var c = C();
var b = A().B();
var c = A().C();
var a = B().C().A();
In case of A().B().C(), you do not have access to the instances of A and B.
Can you elaborate a bit more on what is your deal?
OLD ANSWER:
What you have there is madness as you basically merge three constructors and make it seem that `WorkerBee` and `Employee` are actually instantiated while they are not.
I'm not going to question the new A().B().C() notation even though I find it quite messed up.
You probably want to make use of the instanceof operator the following way.
var A = function (x) {
if (!(this instanceof A)) return new A(x);
this.x = x;
};
var B = function (y) {
if (!(this instanceof B)) return new B(y);
this.y = y;
};
var C = function () {
if (!(this instanceof C)) return new C();
};
A.prototype.B = B;
B.prototype.C = C;
You can now call new A() and A(), new B() and B() and new C() and C() interchangeably while achieving the same result as both of the calls always return an instance of the constructor.
new A() instanceof A === true
new A().B() instanceof B === true
new A().B().C() instanceof C === true
Based on the comments, you seem to have the belief that you have to use this odd, verbose mechanism in order to have inheritance between Employee <- WorkerBee <- Engineer (and such), but you don't; normal inheritance is all you need for this:
// ==== Employee
function Employee(id) {
this.id = id;
}
// Add Employee methods to Employee.prototype, e.g.:
Employee.prototype.getId = function() {
return this.id;
};
// ==== WorkerBee, derived from Employee
function WorkerBee(id, project) {
// Inheritance, part 1: Chain to the base constructor
Employee.call(this, id);
// WorkerBee stuff
this.project = project;
}
// Inheritance, part 2: Create the object to use for WorkerBee
// instance prototypes, using Employee.prototype as its prototype.
WorkerBee.prototype = Object.create(Employee.prototype);
WorkerBee.prototype.constructor = WorkerBee;
// Add WorkerBee methods to WorkerBee.prototype, e.g.:
WorkerBee.prototype.getProjectName = function() {
return this.project;
};
// ==== Engineer, derived from WorkerBee
function Engineer(id, project) {
// Inheritance, part 1: Chain to the base constructor
WorkerBee.call(this, id, project);
}
// Inheritance, part 2: Create the object to use for Engineer
// instance prototypes, using WorkerBee.prototype as its prototype.
Engineer.prototype = Object.create(WorkerBee.prototype);
Engineer.prototype.constructor = Engineer;
// Add Engineer methods to Engineer.prototype, e.g.:
Engineer.prototype.getDept = function() {
return "Engineering";
};
// ==== Usage
var mark = new Engineer("5", "Secret Project");
snippet.log(mark.getId()); // "5"
snippet.log(mark.getProjectName()); // "Secret Project"
snippet.log(mark.getDept()); // "Engineering"
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
That's the standard way to do prototypical inheritance using constructor functions in JavaScript (for now; in ES6, you'd use the new class feature, which does basically the same thing, with some syntactic sugar). Just add Manager (derived from Employee) and SalesPerson (derived from WorkerBee).
On old browsers, you may need a partial polyfill for Object.create, which looks like this:
if (!Object.create) {
Object.create = function(proto, props) {
if (typeof props !== "undefined") {
throw "The two-argument version of Object.create cannot be polyfilled.";
}
function ctor() { }
ctor.prototype = proto;
return new ctor();
};
}
There are transpilers for taking ES6 source with class and turning it into ES5 code. There's also my Lineage script, which makes inheritance a lot less verbose.

Pattern for enforcing new in javascript

I have been reading JavaScript Patterns book by Stoyan Stefanov and one of the patterns to enforcing the new operator for constructor functions goes like this
function Waffle() {
if (!(this instanceof Waffle)) {
return new Waffle();
}
this.tastes = "yummy";
}
Waffle.prototype.wantAnother = true;
when writing this way you can invoke Waffle either one of these ways
var first = new Waffle(),
second = Waffle();
I think this is a helpful feature not sure if it's implemented in future versions of ecma/javascript
I came up with something on my own that I thought could just copy and paste each time when creating a constructor function
something like this
function checkInstance (name) {
if (name.constructor.name === undefined) {
return "construct it"
} else {
return false;
}
}
function Waffle() {
var _self = checkInstance.call(this, this);
if (_self === "construct it") {
return new Waffle()
}
this.tastes = "yummy"
}
var waffle = Waffle()
waffle
Therefore I can invoke Waffle either way new Waffle or Waffle() and still have it return an object
My problem that I'm having is here
if (_self === "construct it") {
return new Waffle()
}
Is there anyway I can refer to new Waffle() without referring to the actual name of the constructor function meaning so I could copy and paste this each time and not have to change anything. Meaning I could I save Waffle() as a variable and do something like
return new var
I wish I could use this.name but that doesn't work either until it is invoked.
I have a feeling I can't but wanted to at least ask some of the people here on stack overflow if it was a possibility
Again your comments and feedback is appreciated
I have a better solution. This is what you're currently doing:
function Waffle() {
if (!(this instanceof Waffle))
return new Waffle;
this.tastes = "yummy";
}
Waffle.prototype.wantAnother = true;
This pattern isn't really nice because you're mixing the code to construct a new object with the code to check if the new keyword is being used.
I've mentioned before that you shouldn't use the new keyword in JavaScript as it breaks functional features. Instead let's create another function which does the same thing:
Function.prototype.new = (function () {
return function () {
functor.prototype = this.prototype;
return new functor(this, arguments);
};
function functor(constructor, args) {
return constructor.apply(this, args);
}
}());
This function allows you to create an instance of a function as follows:
var waffle = Waffle.new();
However we don't want to use new at all. So to do away with it we'll create a function which wraps a constructor as follows:
function constructible(constructor) {
function functor() { return Function.new.apply(constructor, arguments); }
functor.prototype = constructor.prototype;
return functor;
}
Now we can define the Waffle function as follows:
var Waffle = constructible(function () {
this.tastes = "yummy";
});
Waffle.prototype.wantAnother = true;
Now you can create objects with or without using new:
var first = new Waffle;
var second = Waffle();
Note: The constructible function is pretty slow. Use the following version of constructible instead - it's a little faster:
function constructible(constructor) {
constructor = Function.bind.bind(constructor, null);
function functor() { return new (constructor.apply(null, arguments)); }
functor.prototype = constructor.prototype;
return functor;
}
Personally I wouldn't use either of these two methods. I would just remember to write new, or (more likely) I would restructure my code as follows:
var waffle = {
create: function () {
var waffle = Object.create(this);
waffle.tastes = "yummy";
return waffle;
},
wantAnother: true
};
var first = waffle.create();
var second = waffle.create();
If you want to know more about this pattern then read the following answer: https://stackoverflow.com/a/17008403/783743
You could use something like this:
var Waffle = (function() {
function Waffle() {
this.tastes = "yummy"
}
return exportCtor( Waffle );
})();
var waffle = Waffle();
alert(waffle.tastes);
console.log(Waffle);
/*
function ConstructorProxy() {
"use strict";
return new Constructor();
}
*/
http://jsfiddle.net/ywQJF/
It handles variable arguments too
arguments.callee, which refers to the current function, is the most simple solution. It's is deprecated, though, so use it at your own risk.
function Waffle() {
if (!(this instanceof arguments.callee))
return new arguments.callee();
this.tastes = 'yummy';
}
It's a hard problem also because you probably want to preserve the arguments you're passing, as Vinothbabu mentioned. But if you real intention is enforcing new, you could simply throw an error, which is a simple two lines of code:
if (!(this instanceof Waffle))
throw new Error('Constructor called without new');
You could even wrap it in a function:
function cons(C) {
var c = function () {
if (!(this instanceof c))
throw new Error('Constructor called without new');
C.apply(this, arguments);
};
c.prototype = C.prototype;
return c;
}
var Waffle = cons(function () {
this.tastes = 'yummy';
});
Waffle.prototype.wantAnother = function () {
return true;
};
new Waffle(); // { tastes: 'yummy', 'wantAnother': true }
Waffle(); // throws error
Now Waffle must be called with new -- otherwise, it throws an error.
The best approach, in my opinion, is not to enable yourself to invoke things incorrectly:
function Waffle() {
if (!(this instanceof Waffle)) {
throw "Waffles need to be fresh or they're gross. Use 'new'.";
}
}
But, if you simply must enable yourself to write inconsistent code, make initialization a separate step.
function Waffle(options) {
var o = options || {};
if (this instanceof Waffle) {
this.init = function() {
/* this is really your constructor */
console.log("initializing ... ");
}
if (!o.__do_not_initialize) {
this.init(arguments);
}
} else {
var rv = new Waffle( { __do_not_initialize: true } );
rv.init(arguments);
return rv;
}
}
If you want to force consistency the other way -- never using the new keyword, create a builder function:
function BuildWaffle(options) {
var o = options || {};
if (this instanceof WaffleBuilder) {
throw "BuildWaffle cannot be instantiated.";
}
var Waffle = function Waffle() { /* whatever */ }
Waffle.prototype.doStuff = function() { /* whatever else */ }
var rv = new Waffle(options);
return rv;
}
There is simpler way how to enforce creation of new object even without new:
function Waffle() {
return {tastes:"yummy"};
}
var a = Waffle();
var b = new Waffle();
alert(a.tastes); // yummy
alert(b.tastes); // yummy
Explanation
Using new with function, there are two possibilities:
the function returns object: the object is the result of the new function() expression
the function doesn't return object: the function itself with new context is returned
See the ECMA script documentation
Workaround: prototype and arguments
function Waffle(taste,how) {
return {
tastes: taste+" "+how,
__proto__: Waffle.prototype
}
}
Waffle.prototype.wantmore = "yes";
var a = Waffle("yummy","much");
var b = new Waffle("gummy","little");
console.log(a.tastes,b.tastes); // yummy much, gummy little
console.log(a.wantmore,b.wantmore); // yes, yes
This deserves a fiddle.
Note: constructor.name (which you used in your pattern) is not standard
Note 2: __proto__ is also not standard, but is supported by modern browsers and will be standardized in ES6.
if (!(this instanceof Waffle)) {
return new Waffle();
}
This has two problems...
one that it won 't work in an anonymous function which has no name
it loses all arguments sent to the constructor.
Using a more generic approach might look something more like this:
if (!instanceExists(this, arguments)) {
return requireInstance(this, arguments);
}
This approach ensures that the constructor is called with new, without having to state the function'
s name, andadds all arguments sent to the constuctor so they aren 't lost during the process.
Here 's the full code for the above:
Function.prototype.callNew = function (args) {
var a = [];
for (var i = 0; i < args.length; i++) a.push("a[" + i + "]");
var fn = new Function("var a=arguments;return new this(" + a.join(",") + ");");
return fn.apply(this, args);
}
function instanceExists(t, args) {
if (t instanceof args.callee) {
return true;
} else {
return false;
}
}
function requireInstance(t, args) {
var fn = args.callee;
if (!instanceExists(t, args)) {
return fn.callNew(args);
}
}
function Waffle(one, two, three) {
if (!instanceExists(this, arguments)) {
return requireInstance(this, arguments);
}
this.one = one;
this.two = two;
this.three = three;
}
Waffle.prototype.serve = function () {
var out = [];
for (var j in this) {
if (!this.hasOwnProperty(j)) continue;
out.push(j + ': ' + this[j]);
}
return ' {
' + out.join(",\n") + '
}
';
}
A fiddle for you to play with.
http://jsfiddle.net/RkPpH/
var waffle = Waffle(1, 2, 3);
alert(waffle.serve());
I didn't get a sense of whether this was client or server-side, but a pattern I use sometimes goes as follows. I use this in Node but have attempted to make it a possible client-side solution as well - the Node-specific stuff is commented out but there for reference depending on your environment.
First, I create something to be used along the lines of a traditional OO base or super class like so:
//// Node:
//module.exports.Base = Base;
function Base(opts) {
var self = this;
if (!(self instanceof Base)) return new Base(opts);
self.opts = opts || {};
}
Upon which you can define your methods, in usual the fashion. You can even manually throw if the method should be provided by subclasses implementing something like abstract:
// commonMethod is available to subclasses:
Base.prototype.commonMethod = function () {
var self = this;
//access self.opts to get the constructor arguments.
//makes self always point to the right object.
}
// Provide abstractMethod, but subclass is responsible for implementation:
Base.prototype.abstractMethod = function () {
//or throw an error if this should be implemented by subclasses:
throw new Error('implement me');
}
Now you can do this:
//// If using Node:
//var inherits = require('util').inherits;
//var Parent = require('./Base').Base;
function Sub (opts) {
var self = this;
//// If using node and you want super_ to be called prior to creating a new Sub:
//if(Sub.super_) Sub.super_.call(this, opts);
// Always do this:
if (!(self instanceof Sub)) return new Sub(opts);
//// If using node and you are ok with super_ called after creating new Sub:
//if(Sub.super_) Sub.super_.call(this, opts);
//// otherwise:
parent(opts);
}
//// If using Node:
//inherits(Sub, Base);
//// Otherwise:
Sub.prototype.constructor = Base;
Sub.prototype.parent = Base.prototype;
//and provide the implementation of abstractMethod:
Sub.prototype.abstractMethod() {
//...
}
And to formally answer the specific question, all of the
if (!(self instanceof Sub)) return new Sub(opts);
is where you get the guaranteed new situation.

How can I construct an object using an array of values for parameters, rather than listing them out, in JavaScript?

Is this possible? I am creating a single base factory function to drive factories of different types (but have some similarities) and I want to be able to pass arguments as an array to the base factory which then possibly creates an instance of a new object populating the arguments of the constructor of the relevant class via an array.
In JavaScript it's possible to use an array to call a function with multiple arguments by using the apply method:
namespace.myFunc = function(arg1, arg2) { //do something; }
var result = namespace.myFunc("arg1","arg2");
//this is the same as above:
var r = [ "arg1","arg2" ];
var result = myFunc.apply(namespace, r);
It doesn't seem as if there's anyway to create an instance of an object using apply though, is there?
Something like (this doesn't work):
var instance = new MyClass.apply(namespace, r);
Try this:
var instance = {};
MyClass.apply( instance, r);
All the keyword "new" does is pass in a new object to the constructor which then becomes the this variable inside the constructor function.
Depending upon how the constructor was written, you may have to do this:
var instance = {};
var returned = MyClass.apply( instance, args);
if( returned != null) {
instance = returned;
}
Update: A comment says this doesn't work if there is a prototype. Try this.
function newApply(class, args) {
function F() {
return class.apply(this, args);
}
F.prototype = class.prototype;
return new F();
}
newApply( MyClass, args);
Note that
new myClass()
without any arguments may fail, since the constructor function may rely on the existence of arguments.
myClass.apply(something, args)
will fail in many cases, especially if called on native classes like Date or Number.
I know that "eval is evil", but in this case you may want to try the following:
function newApply(Cls, args) {
var argsWrapper = [];
for (var i = 0; i < args.length; i++) {
argsWrapper.push('args[' + i + ']');
}
eval('var inst = new Cls(' + argsWrapper.join(',') + ');' );
return inst;
}
Simple as that.
(It works the same as Instance.New in this blog post)
Hacks are hacks are hacks, but perhaps this one is a bit more elegant than some of the others, since calling syntax would be similar to what you want and you wouldn't need to modify the original classes at all:
Function.prototype.build = function(parameterArray) {
var functionNameResults = (/function (.{1,})\(/).exec(this.toString());
var constructorName = (functionNameResults && functionNameResults.length > 1) ? functionNameResults[1] : "";
var builtObject = null;
if(constructorName != "") {
var parameterNameValues = {}, parameterNames = [];
for(var i = 0; i < parameterArray.length; i++) {
var parameterName = ("p_" + i);
parameterNameValues[parameterName] = parameterArray[i];
parameterNames.push(("parameterNameValues." + parameterName));
}
builtObject = (new Function("parameterNameValues", "return new " + constructorName + "(" + parameterNames.join(",") + ");"))(parameterNameValues);
}
return builtObject;
};
Now you can do either of these to build an object:
var instance1 = MyClass.build(["arg1","arg2"]);
var instance2 = new MyClass("arg1","arg2");
Granted, some may not like modifying the Function object's prototype, so you can do it this way and use it as a function instead:
function build(constructorFunction, parameterArray) {
var functionNameResults = (/function (.{1,})\(/).exec(constructorFunction.toString());
var constructorName = (functionNameResults && functionNameResults.length > 1) ? functionNameResults[1] : "";
var builtObject = null;
if(constructorName != "") {
var parameterNameValues = {}, parameterNames = [];
for(var i = 0; i < parameterArray.length; i++) {
var parameterName = ("p_" + i);
parameterNameValues[parameterName] = parameterArray[i];
parameterNames.push(("parameterNameValues." + parameterName));
}
builtObject = (new Function("parameterNameValues", "return new " + constructorName + "(" + parameterNames.join(",") + ");"))(parameterNameValues);
}
return builtObject;
};
And then you would call it like so:
var instance1 = build(MyClass, ["arg1","arg2"]);
So, I hope those are useful to someone - they allow you to leave the original constructor functions alone and get what you are after in one simple line of code (unlike the two lines you need for the currently-selected solution/workaround.
Feedback is welcome and appreciated.
UPDATE: One other thing to note - try creating instances of the same type with these different methods and then checking to see if their constructor properties are the same - you may want that to be the case if you ever need to check the type of an object. What I mean is best illustrated by the following code:
function Person(firstName, lastName) {
this.FirstName = firstName;
this.LastName = lastName;
}
var p1 = new Person("John", "Doe");
var p2 = Person.build(["Sara", "Lee"]);
var areSameType = (p1.constructor == p2.constructor);
Try that with some of the other hacks and see what happens. Ideally, you want them to be the same type.
CAVEAT: As noted in the comments, this will not work for those constructor functions that are created using anonymous function syntax, i.e.
MyNamespace.SomeClass = function() { /*...*/ };
Unless you create them like this:
MyNamespace.SomeClass = function SomeClass() { /*...*/ };
The solution I provided above may or may not be useful to you, you need to understand exactly what you are doing to arrive at the best solution for your particular needs, and you need to be cognizant of what is going on to make my solution "work." If you don't understand how my solution works, spend time to figure it out.
ALTERNATE SOLUTION: Not one to overlook other options, here is one of the other ways you could skin this cat (with similar caveats to the above approach), this one a little more esoteric:
function partial(func/*, 0..n args */) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var allArguments = args.concat(Array.prototype.slice.call(arguments));
return func.apply(this, allArguments);
};
}
Function.prototype.build = function(args) {
var constructor = this;
for(var i = 0; i < args.length; i++) {
constructor = partial(constructor, args[i]);
}
constructor.prototype = this.prototype;
var builtObject = new constructor();
builtObject.constructor = this;
return builtObject;
};
Enjoy!
what about a workaround?
function MyClass(arg1, arg2) {
this.init = function(arg1, arg2){
//if(arg1 and arg2 not null) do stuff with args
}
init(arg1, arg2);
}
So how you can:
var obj = new MyClass();
obj.apply(obj, args);
One possibility is to make the constructor work as a normal function call.
function MyClass(arg1, arg2) {
if (!(this instanceof MyClass)) {
return new MyClass(arg1, arg2);
}
// normal constructor here
}
The condition on the if statement will be true if you call MyClass as a normal function (including with call/apply as long as the this argument is not a MyClass object).
Now all of these are equivalent:
new MyClass(arg1, arg2);
MyClass(arg1, arg2);
MyClass.call(null, arg1, arg2);
MyClass.apply(null, [arg1, arg2]);

Categories