Является ли eval единственным способом создания функций с динамически определяемой арностью в JavaScript?

Я использую шпионскую библиотеку JavaScript, simple-spy.

Я обнаружил, что при слежке за данной функцией получающийся шпион всегда имеет арность 0.

Это создает проблему при использовании этой функции каррирования.

Итак, я отправил запрос на включение, который добавляет прозрачность в шпионскую библиотеку .

Код выглядит следующим образом:

function spy(fn) {
    const inner = (...args) => {
        stub.callCount++;
        stub.args.push(args);
        return fn(...args);
    };

    // ends up a string like
    // 'a,b,c,d'
    // depending on the `fn.length`
    const stubArgs = Array(fn.length)
        .fill(null)
        .map((m, i) => String.fromCodePoint(97 + i))
        .join();

    const stubBody = 'return inner(...arguments);';

    // this seems to be the only way
    // to create a function with
    // programmatically specified arity
    const stub = eval(
        // the wrapping parens is to
        // prevent it from evaluating as
        // a function declaration
        `(function (${stubArgs}) { ${stubBody} })`
    );

    stub.reset = () => {
        stub.callCount = 0;
        stub.args = [];
    };

    stub.reset();

    return stub;
}

exports.spy = spy;

Кажется, это работает.

Можно ли это сделать без использования eval?

Можно ли еще меньше использовать eval?

Я знаю, что есть и другие проблемы с этой реализацией шпиона. Это упрощенно, и это работает для моего варианта использования до сих пор.


person mightyiam    schedule 28.10.2016    source источник
comment
Вы можете использовать Function и установить аргументы. Не намного лучше, но лучше. Вы также можете установить .length с помощью defineProperty для функций   -  person Benjamin Gruenbaum    schedule 29.10.2016


Ответы (1)


Как писал Бенджамин, я использовал простой:

function spy(fn) {
    const stub = (...args) => {
        stub.callCount++;
        stub.args.push(args);
        return fn(...args);
    };

    stub.reset = () => {
        stub.callCount = 0;
        stub.args = [];
    };

    stub.reset();

    Object.defineProperty(stub, 'length', {value: fn.length});

    return stub;
}

exports.spy = spy;

Гораздо лучше выглядит.

person mightyiam    schedule 28.10.2016