How to pass arguments dynamically to a new call?

Asked

Viewed 125 times

3

If I have a Javascript function and want to call it by passing a list of arguments, use apply:

var x = f(1,2,3);
var x = f.apply(null, [1,2,3]);

For the first time, I came across a case where I need to call one builder with a list of arguments, and the first thing I tried (even suspecting it would go wrong) was to simply do the same:

var x = new f(1,2,3);
var x = new f.apply(null, [1,2,3]);

And in fact it didn’t work... Is there any way to do that? I have to create several objects, in a loop, and I was forced to do so:

var x = new f(lista[0], lista[1], lista[2]);

That is not so bad in the case of a builder with only 3 parameters, but I wonder if there is a more concise or "elegant means".

1 answer

3


In Soen there is a interesting answer with this solution:

function construtor(Construtor) {
    return new (Construtor.bind.apply(Construtor, arguments));
}

Basically a function that:

  • changes indicator/scope of the this to the Class/Constructor assigned to it
  • applies the arguments passed to it (not indicated in the function declaration because they are optional)
  • returns new of this builder.

An example would be:

var Pessoa = function (nome) {
    this.nome = nome || 'Anónimo';
    this.getNome = function () {
        return this.nome;
    }
}

var Ana = new Pessoa('Ana');
console.log(Ana.getNome()); // "Ana"

function construtor(Construtor) {
    return new (Construtor.bind.apply(Construtor, arguments));
}

var Pedro = construtor(Pessoa, 'Pedro');
console.log(Pedro.getNome()); // "Pedro"

var Maria = construtor(Pessoa, 'Maria');
console.log(Maria.getNome()); // "Maria"

jsFiddle: http://jsfiddle.net/60snrx9L/


Note:

When we use construtor internally he does Classe.bind.apply(Classe, argumentos), which means that the .bind will be called with context Classe and with arguments from the variable argumentos. Since the .bind consumes the first argument as the context of the function that becomes "binded", that first element of the array argumentos is discarded once the new creates a new context.

Another way, without having discardable elements in the arguments it may be so:

function construct(constructor, args) {
    function F() {
        return constructor.apply(this, args);
    }
    F.prototype = constructor.prototype;
    return new F();
}
  • Interesting! Only that way I’d have to do construtor.apply(null, [f].concat(lista)). But nothing a little adjustment won’t fix: function construtor(Construtor, args) { return new (Construtor.bind.apply(Construtor, [null].concat(args))); } and to use construtor(f, lista). Example

  • @mgibsonbr good fit. The .unshift() would also (http://jsfiddle.net/60snrx9L/2/) but your version uses less characters :)

  • The problem of unshift is that it causes a side effect on the list passed as argument, while the concat is being used in a new list.

  • @mgibsonbr truth, well seen.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.