Предисловие

В век многопроцессорных быстрых процессоров, распределенных систем и облачных вычислений о производительности легко забыть. Тем не менее, отказ от использования передовых практик и оптимизации кода во всем коде может стоить вам или вашей компании тысячи евро в месяц.

Решение

Оптимизацией в этом направлении может быть замена больших операторов switch или if на хеш-таблицы.

Давайте теперь представим несколько реальных примеров:

(1) Простой пример:

Давайте представим, что есть пересечение, и мы реализуем функцию-обработчик, чтобы найти угол в градусах, на который мы должны повернуть, задав в качестве входных данных одну из строк («влево», «вправо», «прямо», «назад»). Если мы не введем одно из этих слов, функция должна вернуть «неправильный ввод».

Давайте посмотрим, как это реализовать с помощью оператора switch (мы могли бы также использовать эквивалентный оператор if):

const handlerFunc = value => {
  const handlerRight = () => 'angle:' + '90';
  const handlerStraight = () => 'angle:' + '180';
  const handlerLeft = () => 'angle:' + '270';
  const handlerBack = () => 'angle:' + '360';
  const handlerWrongInput = () => 'wrong input';

 switch(value) {
  case 'right':
    return handlerRight();
    break;
  case 'straight':
    return handlerStraight();
    break;
  case 'left':
    return handlerLeft();
    break;
  case 'back':
    return handlerBack();
    break;
  default:
    return handlerWrongInput();
  }
}
console.log(handlerFunc('right')); // angle:90
console.log(handlerFunc('straight')); // angle:180
console.log(handlerFunc('left')); // angle:270
console.log(handlerFunc('back')); // angle:360
console.log(handlerFunc('whatever')); // wrong input

Вроде все отлично работает. Хотя, если у нас много случаев, и допустим, что ни один из них не соответствует, что означает, что вариант по умолчанию должен выполняться, нам придется проверять все варианты, пока мы, наконец, не дойдем до случая по умолчанию. Это означает временную сложность O (n).

Вопрос в том: можем ли мы улучшить сложность?

Ответ: да! Используя хеш-таблицу, например, объект javascript.

Это повысит сложность до O (1).

Давайте посмотрим, как мы можем это реализовать:

const handlerFunc = value => {
  const handlerRight = () => 'angle:' + '90';
  const handlerStraight = () => 'angle:' + '180';
  const handlerLeft = () => 'angle:' + '270';
  const handlerBack = () => 'angle:' + '360';
  const handlerWrongInput = () => 'wrong input';

  const handlerObject = {
    'right': handlerRight,
    'straight': handlerStraight,
    'left': handlerLeft,
    'back': handlerBack,
  };

  if (handlerObject[value]) return handlerObject[value]();
  else return handlerWrongInput();
}

В этом случае, если мы снова зарегистрируем выходные данные, мы получим те же результаты, что и раньше. Хотя мы улучшим сложность до O (1)!

Мы также использовали оператор if else для обработки случая по умолчанию.

До сих пор все в порядке, но что, если наши функции-обработчики по умолчанию не содержат углов, но мы хотим передать их в качестве аргументов?. Или, может быть, мы хотим изменить единицы измерения углов на радиусы вместо градусов?

В этом случае мы могли бы изменить значения объекта, чтобы они были самими объектами!

Одним ключом каждого объекта может быть functionName, а другим - param.

Реализуем эту идею:

const handlerFunc = value => {
  const handlerRight = angle => 'angle:' + angle;
  const handlerStraight = angle => 'angle:' + angle;
  const handlerLeft = angle => 'angle:' + angle;
  const handlerBack = angle => 'angle:' + angle;
  const handlerWrongInput = () => 'wrong input';
  // we could have replaced the angles in rads as well
  const handlerObject = {
    'right': {functionName: handlerRight, param: '90'},
    'straight': {functionName: handlerStraight, param: '180'},
    'left': {functionName: handlerLeft, param: '270'},
    'back': {functionName: handlerBack, param: '360'},
  };
  if (handlerObject[value]) return     handlerObject[value].functionName(handlerObject[value].param);
 else return handlerWrongInput();
}

Теперь, если мы снова запустим тот же console.logs, у нас будут точно такие же выходные данные, хотя мы сможем легко изменить каждый параметр, изменяя значение параметра, как нам нравится, внутри handlerObject.

(2) Немного более сложный пример:

В предыдущем примере все функции-обработчики были одинаковыми (кроме той, которая обрабатывает неправильный ввод), и мы могли использовать одну функцию-обработчик вместо первых 4.

Но что, если наши функции-обработчики разные и также имеют другое количество аргументов?

Представим себе проблему:

Нам нужно рассчитать площадь геометрической формы в зависимости от точных характеристик формы.

Мы сможем вычислить площадь трех фигур («квадрат», «круг» и «треугольник»), которые будут нашими входными данными handleFunc.

Для этого нам понадобятся:

  • длина стороны квадрата (a): один вход для handlerSquare (A = a²).
  • радиус круга (r): один вход для обработчикаCircle (A = πr²).
  • базовая длина (b) и высота (h) треугольника: два входа для handlerTriangle (A = b * h / 2).

В этом случае реализация может быть:

const handlerFunc = value => {
  const handlerSquare = params => Math.pow(params.a, 2);
  const handlerCircle = params => Math.PI * Math.pow(params.r, 2);
  const handlerTriangle = params => params.b * params.h / 2;
  const handlerWrongInput = () => 'wrong input';

  const handlerObject = {
    'square': {functionName:handlerSquare, params: {a: 2}},
    'circle': {functionName:handlerCircle, params: {r: 1}},
    'triangle': {functionName:handlerTriangle, params: {b: 4, h:3   }},
  };
  if (handlerObject[value]) return   handlerObject[value].functionName(handlerObject[value].params);
  else return handlerWrongInput();
}

console.log(handlerFunc('square')); //4
console.log(handlerFunc('circle')); //3.141592653589793
console.log(handlerFunc('triangle')); //6
console.log(handlerFunc('whatever')); // wrong input

В этом случае, чтобы иметь возможность добавлять больше аргументов, мы использовали объект (params) вместо одного параметра.

Таким образом, каждый обработчик может иметь свои собственные параметры, а также различное количество параметров.

Фото Кристофера Робина Эббингауза