Хаки - это хаки, но они, возможно, немного более элегантны, чем некоторые другие, поскольку синтаксис вызова будет аналогичен тому, что вы хотите, и вам вообще не нужно будет изменять исходные классы:
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;
};
Теперь вы можете сделать одно из следующих действий для создания объекта:
var instance1 = MyClass.build(["arg1","arg2"]);
var instance2 = new MyClass("arg1","arg2");
Конечно, некоторым может не понравиться изменение прототипа объекта Function, поэтому вы можете сделать это таким образом и использовать вместо этого функцию:
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;
};
И тогда вы бы назвали это так:
var instance1 = build(MyClass, ["arg1","arg2"]);
Итак, я надеюсь, что они кому-то пригодятся - они позволят вам оставить исходные функции конструктора в покое и получить то, что вам нужно, в одной простой строке кода (в отличие от двух строк, необходимых для выбранного в настоящее время решения / обходного пути). .
Обратная связь приветствуется и приветствуется.
ОБНОВЛЕНИЕ: Еще одна вещь, на которую следует обратить внимание - попробуйте создать экземпляры одного и того же типа с помощью этих различных методов, а затем проверить, совпадают ли их свойства конструктора, - вы можете захотеть, чтобы это было так, если вам когда-либо понадобится проверить тип объекта. То, что я имею в виду, лучше всего иллюстрируется следующим кодом:
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);
Попробуйте это с некоторыми другими хаки и посмотрите, что произойдет. В идеале вы хотите, чтобы они были одного типа.
CAVEAT: как отмечено в комментариях, это не будет работать для тех функций конструктора, которые созданы с использованием синтаксиса анонимной функции, т.е.
MyNamespace.SomeClass = function() { /*...*/ };
Если вы не создадите их так:
MyNamespace.SomeClass = function SomeClass() { /*...*/ };
Решение, которое я предоставил выше, может или не может быть полезным для вас, вам нужно точно понимать, что вы делаете, чтобы найти лучшее решение для ваших конкретных нужд, и вы должны быть в курсе того, что происходит в будущем мое решение "работа". Если вы не понимаете, как работает мое решение, потратьте время на его выяснение.
АЛЬТЕРНАТИВНОЕ РЕШЕНИЕ: не один, чтобы упускать из виду другие варианты, вот один из других способов, которым вы могли бы снять шкуру с этой кошки (с аналогичными предостережениями к вышеописанному подходу), этот более эзотерический:
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;
};
Наслаждайтесь!