Hacks are hacks are hacks, but maybe this one stands out a bit more for its elegance compared to others. The calling syntax remains similar to what you desire without the need to alter the original classes:
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 create an object using either of these methods:
var instance1 = MyClass.build(["arg1","arg2"]);
var instance2 = new MyClass("arg1","arg2");
However, some may not favor modifying the Function object's prototype. Thus, you can achieve the same functionality by treating it as a separate function like so:
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;
};
Usage would be as follows:
var instance1 = build(MyClass, ["arg1","arg2"]);
These methods allow you to avoid altering the original constructor functions and achieve your goal in just one line of code, unlike other solutions that require two lines.
Feel free to provide feedback.
UPDATE: It is worth noting that creating instances of the same type using different methods may result in their constructor properties being different. This could impact scenarios where checking the type of an object is necessary. Consider the following code snippet:
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 this with various other hacks to observe the outcome. Ideally, you'd want them to be the same type.
CAVEAT: As mentioned in the comments, this method may not work for constructor functions created using anonymous function syntax, such as
MyNamespace.SomeClass = function() { /*...*/ };
Unless they are defined as follows:
MyNamespace.SomeClass = function SomeClass() { /*...*/ };
The solution provided may or may not suit your needs. Understanding the process involved is crucial in determining the best solution for your specific requirements. Be aware of the operations to make this solution effective. If unsure, take the time to comprehend how it works.
ALTERNATE SOLUTION: Exploring alternative approaches, here is another way to achieve a similar result, albeit slightly more complex:
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!