Каковы альтернативы eval в JavaScript? - PullRequest
13 голосов
/ 08 января 2010

У меня есть немного кода, который выглядит так:

function StrippedExample(i1, i2, i3, i4, i5, i6, i7, i8) {
    this.i = [];
    for (var i=1,j=0 ;i<9;i++) {
        var k = eval("i"+i);
        if (k > 0) {
            this.i[j++] = k;
        }
    }
}

Профилировщик FireBug утверждает, что второй самой длинной функцией является eval (), занимающая почти 6% времени выполнения.

Все говорят, что eval - это ЗЛО (как в плохом) и медленное (как я обнаружил), но я ничего больше не могу сделать - сервер просто извлекает данные из базы данных и подталкивает браузер.

Какие у меня есть альтернативы? Я мог бы сделать то же самое, что я делаю здесь на сервере, но это только увеличивает нагрузку вверх по цепочке. Я не могу изменить структуру базы данных, так как все привязано к этим 8 переменным и является огромным мероприятием.

Ответы [ 9 ]

14 голосов
/ 08 января 2010
function StrippedExample(i1, i2, i3, i4, i5, i6, i7, i8) {
    var args = [i1, i2, i3, i4, i5, i6, i7, i8]; // put values in an array
    this.i = [];
    for (var i=0,j=0 ;i<8;i++) { // now i goes from 0-7 also
        var k = args[i]; // get values out
        if (k > 0) {
            this.i[j++] = k;
        }
    }
}

Приведенный выше код может быть еще более упрощен, я просто внес минимальное изменение, чтобы избавиться от eval. Вы можете избавиться от j, например:

function StrippedExample(i1, i2, i3, i4, i5, i6, i7, i8) {
    var args = [i1, i2, i3, i4, i5, i6, i7, i8];
    this.i = [];
    for (var i = 0; i < args.length; i++) {
        var k = args[i];
        if (k > 0) { this.i.push(k); }
    }
}

эквивалентно. Или, чтобы использовать встроенный объект arguments (чтобы избежать списка параметров в двух местах):

function StrippedExample(i1, i2, i3, i4, i5, i6, i7, i8) {
    this.i = [];
    for (var i = 1; i < arguments.length; i++) {
        var k = arguments[i];
        if (k > 0) { this.i.push(k); }
    }
}

Даже если вы не фильтровали список, вы не хотите делать что-то вроде this.i = arguments, потому что arguments не является настоящим массивом; у него есть свойство callee, которое вам не нужно, и отсутствуют некоторые методы массива, которые могут вам понадобиться в i. Как уже отмечали другие, если вы хотите быстро преобразовать объект arguments в массив, вы можете сделать это с помощью следующего выражения:

Array.prototype.slice.call(arguments)

Вы можете использовать это вместо var args = [i1, i2 ... строк выше.

7 голосов
/ 08 января 2010

Вы просто создаете массив из своей функции из 8 аргументов, удаляя те, которые меньше или равны нулю.

Следующий код эквивалентен, и он будет работать для любого произвольного числа аргументов:

function StrippedExample() {
  var args = [];

  for (var i = 0; i < arguments.length; i++) {
    if (arguments[i] > 0) {
      args.push(arguments[i]);
    }
  }
  //...
}
5 голосов
/ 08 января 2010
  1. Вызов функции с одним аргументом - массивом
  2. Использовать аргументы объект
4 голосов
/ 08 января 2010

Одна альтернатива передаче массива в вашу функцию вместо отдельных аргументов:

StrippedExample([3, 1, 4, 1, 5, 9, 2, 6])

Тогда ваш код будет:

function StrippedExample(inArray) {
    this.i = [];
    for (var i=0,j=0 ;i<inArray.length;i++) {
        var k = inArray[i];
        if (k > 0) {
            this.i[j++] = k;
        }
    }
}

Если вам действительно нужно передать отдельные аргументы, вы можете получить к ним доступ с помощью массива arguments, который является объектом, который действует как массив (хотя это не совсем так; не все методы Array работают на нем), который выставляет все аргументы, которые были переданы вашей функции; в этом случае их даже не нужно объявлять, но стоит добавить комментарий, указывающий, какого рода аргументы вы ожидаете от пользователей вашего кода:

function StrippedExample(/*i1, i2, i3, i4, i5, i6, i7, i8*/) {
    this.i = [];
    for (var i=0,j=0 ;i<arguments.length;i++) {
        var k = arguments[i];
        if (k > 0) {
            this.i[j++] = k;
        }
    }
}

Если вы гарантированно имеете только 8 элементов, тогда вы можете использовать 8 вместо inArray.length или arguments.length; Я решил использовать более общую версию в моих примерах на случай, если она будет вам полезна.

1 голос
/ 22 мая 2017

Eval альтернатива:

exp = '1 + 1'
x = Function('return ' + exp)()
console.log(x)
1 голос
/ 08 января 2010
function StrippedExample() {

    this.i = [];
    for (var i=1,j=0 ;i<arguments.length;i++) {
        var k = arguments[i];
        if (k > 0) {
            this.i[j++] = k;
        }
    }
}
1 голос
/ 08 января 2010

Этот код должен быть сделан для использования массива arguments, к которому имеет доступ каждая функция Javascript.

Дело не в том, что eval это зло (оно в Лиспе, поэтому должно быть хорошо ), это просто признак взлома - вам нужно что-то, чтобы работать, и вы заставили Это. Это кричит мне: «Автор отказался от хорошего дизайна программирования и просто нашел то, что сработало».

0 голосов
/ 24 марта 2019
  1. Краткий ответ:
StrippedExample=(...a)=>a.filter(i=>i>0);

нет необходимости использовать eval для работы с аргументами.

  1. Исходный код и большинство предлагаемых решений не возвращают результат традиционным способом.
0 голосов
/ 08 января 2010

Принимая во внимание фиксированное количество переменных, вы можете создать их массив вручную и выполнить его цикл. Но если у вас есть переменное количество аргументов, один из способов получить переменные, переданные функции в виде массива:

var args = Array.prototype.slice.call(arguments.callee.caller.arguments);

И ваша функция будет выглядеть так:

function StrippedExample() {
    var args = Array.prototype.slice.call(arguments.callee.caller.arguments);
    for(var i in args) {
        if (args[i] > 0) {
            this.i[j++] = args[i];
        }
    }
}
...