JavaScript: вызов конструктора с произвольным числом аргументов

Есть у нас, предположим, функция и есть у нас массив произвольного количества аргументов для неё. Как нам её вызвать? Очень просто:

function f(a, b, c) {
    // ...
}
var args = [1, 2, 3];
 
f.apply(f, args);

Здорово.
Следующая задача: у нас есть функция-конструктор и массив аргументов для неё. Как нам использовать этот массив совместно с оператором new? Может new f.apply(f, args)? Хрен там, здесь new будет пытаться использовать в качестве конструктора результат от f.apply().

Нам нужно разбить задачу на две:
1. Создать пустой объект, но с нужной цепочкой прототипов.
2. Вызвать на нём конструктор для инициализации.

function applyForConstructor(Constr, args) {
    var instance, Fake;
    Fake = function () {};
    Fake.prototype = Constr.prototype;
    instance = new Fake();
    Constr.apply(instance, args);
    return instance;
}
 
var instance = applyForConstructor(f, [1, 2, 3]);

Здесь нам пришлось создать фиктивный конструктор Fake, чтобы создавать пустой объект, но с нужным наследованием.

Всё здорово, но JavaScript такой язык, который всегда позволяет извращаться и дальше, практически до бесконечности.

В ES5 мы можем уже не создавать фиктивный конструктор:

function applyForConstructor(Constr, args) {
    instance = Object.create(Constr.prototype);    
    Constr.apply(instance, args);
    return instance;
}

Или свести конструктор через замыкание к функции без аргументов:

function createFuncWithoutArgs(f, args) {
    var newF = function () {
        return f.apply(this, args);
    };
    newF.prototype = f.prototype;
    return newF;
}
 
var instance = new (createFuncWithoutArgs(f, args));

Или в том же ES5 использовать bind:

var instance = new (Function.prototype.bind.apply(f, [null].concat(args)));

В общем, много забавных вещей придумать можно.

5 комментариев »

  • Месье знает толк в извращениях. :)

    Алексей, 1.03.2013, 9:44

  • ты мутулз изобретаешь?

    CTAPbIu_MABP, 5.03.2013, 4:05

  • >ты мутулз изобретаешь?

    что конкретно из всего, что там наворочано?

    vasa_c, 5.03.2013, 12:22

  • А для чего это? Я не шибко шарю в JS, но всё же, разве нельзя просто:

    function f(a, b, c) {
    // …
    }

    f(1, 2, 3);
    f(1, 2);
    f(1, 2, 3, 4);
    f();

    Denis, 13.09.2013, 12:40

  • Denis, можно. Но здесь не об этом.

    vasa_c, 13.09.2013, 13:00

Leave a comment