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