varargs parametros operator javascript constructor variadic-functions

parametros - javascript se aplica al constructor, lanzando "parámetro formal con formato incorrecto"



spread javascript (4)

Gracias a las maravillosas respuestas a esta pregunta , entiendo cómo llamar a las funciones javascript con varargs.

Ahora estoy buscando usar aplicar con un constructor

He encontrado información interesante en este post .

pero mi código está arrojando errores

intento 1:

var mid_parser = new Parser.apply(null, mid_patterns);

error:

TypeError: Function.prototype.apply called on incompatible [object Object]

intento 2: intento 1:

var mid_parser = new Parser.prototype.apply(null, mid_patterns);

error:

TypeError: Function.prototype.apply called on incompatible [object Object]

intento 2:

function Parser() { this.comparemanager = new CompareManager(arguments); } mid_patterns = [objA,objB,objC] var mid_parser = new Parser(); Parser.constructor.apply(mid_parser, mid_patterns);

error:

syntax_model.js:91: SyntaxError: malformed formal parameter

intento 3:

var mid_parser = Parser.apply(null, mid_patterns);

error:

TypeError: this.init is undefined // init is a function of Parser.prototype

Tengo una solución por el momento:

function Parser() { if(arguments.length) this.init.call(this,arguments); // call init only if arguments } Parser.prototype = { //... init: function() { this.comparemanager = new CompareManager(arguments); } //... } var normal parser = new Parser(objA,objB,objC); mid_patterns = [objA,objB,objC] var dyn_parser = new Parser(); dyn_parser.init.apply(dyn_parser, mid_patterns);

Esto funciona bastante bien, pero no es tan limpio y universal como me gustaría.

¿Es posible en javascript llamar a un constructor con varargs?


Para completar la solución @CMS y preservar la cadena de prototipos, puede hacer esto:

var mid_parser = {}; mid_parser.__proto__ = Parser.prototype; Parser.apply(mid_parser, mid_patterns);

Como nota al margen, no funcionará con IE 8-.


Podrías usar aplicar y pasar un objeto vacío como this argumento:

var mid_parser = {}; Parser.apply(mid_parser, mid_patterns);

Pero esa solución no se ocupará de la cadena del prototipo.

Podría crear un objeto Parser , utilizando el new operador, pero sin pasar argumentos, y luego usar apply para volver a ejecutar la función de constructor:

var mid_parser = new Parser(); Parser.apply(mid_parser, mid_patterns);


Puede aprovechar el hecho de que puede encadenar constructores utilizando apply(...) para lograr esto, aunque esto requiere la creación de una clase proxy. La función construct() continuación te permite hacer:

var f1 = construct(Foo, [2, 3]); // which is more or less equivalent to var f2 = new Foo(2, 3);

La función construct() :

function construct(klass, args) { function F() { return klass.apply(this, arguments[0]); }; F.prototype = klass.prototype; return new F(args); }

Algún código de muestra que lo usa:

function Foo(a, b) { this.a = a; this.b = b; } Foo.prototype.dump = function() { console.log("a = ", this.a); console.log("b = ", this.b); }; var f = construct(Foo, [7, 9]); f.dump();


Una mejor solución es crear una función de constructor temporal, aplicar el prototipo de la clase que desea (para garantizar que se conserven las cadenas de prototipos) y luego aplicar el constructor manualmente. Esto evita llamar al constructor dos veces innecesariamente ...

applySecond = function(){ function tempCtor() {}; return function(ctor, args){ tempCtor.prototype = ctor.prototype; var instance = new tempCtor(); ctor.apply(instance,args); return instance; } }();

Probé el rendimiento y descubrí que este método es, de hecho, un poco más lento en el caso muy simple. Sin embargo, solo toma la construcción de un único objeto Date () en el constructor para que esto sea más eficiente. Además, no olvide que algunos constructores pueden lanzar excepciones si no se pasan parámetros, por lo que esto también es más correcto.

Mi código de validación:

var ExpensiveClass = function(arg0,arg1){ this.arg0 = arg0; this.arg1 = arg1; this.dat = new Date(); } var CheapClass = function(arg0,arg1){ this.arg0 = arg0; this.arg1 = arg1; } applyFirst = function(ctor, args){ var instance = new ctor(); ctor.apply(instance, args); return instance; } applySecond = function(){ function tempCtor() {}; return function(ctor, args){ tempCtor.prototype = ctor.prototype; var instance = new tempCtor(); ctor.apply(instance,args); return instance; } }(); console.time(''first Expensive''); for(var i = 0; i < 10000; i++){ test = applyFirst(ExpensiveClass ,[''arg0'',''arg1'']); } console.timeEnd(''first Expensive''); console.time(''second Expensive''); for(var i = 0; i < 10000; i++){ test = applySecond(ExpensiveClass ,[''arg0'',''arg1'']); } console.timeEnd(''second Expensive''); console.time(''first Cheap''); for(var i = 0; i < 10000; i++){ test = applyFirst(CheapClass,[''arg0'',''arg1'']); } console.timeEnd(''first Cheap''); console.time(''second Cheap''); for(var i = 0; i < 10000; i++){ test = applySecond(CheapClass,[''arg0'',''arg1'']); } console.timeEnd(''second Cheap'');

Los resultados:

first Expensive: 76ms second Expensive: 66ms first Cheap: 52ms second Cheap: 52ms