Повторное использование той же функции shortcut.js для обработки ввода с клавиатуры

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

Например, у меня есть:

  shortcut.add("0",function() {
    points = -1;
    sec = 0;
  }); 

  shortcut.add("1",function() {
    points = 1;
    sec = 0;
  }); 

  shortcut.add("2",function() {
    points = 2;
    sec = 0;
  }); 

  shortcut.add("3",function() {
    points = 3;
    sec = 0;
  }); 

В идеале я могу обобщить функцию так, чтобы любой введенный ключ был фактически назначен переменной points, за исключением случая, когда пользователь вводит 0. В этом случае переменная points устанавливается в -1.

Есть идеи, как это сделать? Спасибо!

1 ответ

Решение

Цикл с замыканием должен помочь:

for (var i = 0; i <= 9; ++i) {
    (function(i) {  // Capture current value of 'i' in this scope.
        shortcut.add(i.toString(), function() {
            points = i || -1;  // 'i' if 'i' is not 0, else -1.
            sec = 0;
        });
    })(i);
}

Обновите следующий комментарий: Так зачем нам закрытие здесь? А что значит финал (i); имею в виду?

По сути, нам нужно закрытие, потому что анонимные функции передаются shortcut.add() не будет вызван сразу, но когда-нибудь в будущем, после завершения цикла. Захват функций i по ссылке, а не по значению, что означает, что они увидят значение i это актуально во время их запуска, а не во время, когда они определены.

Итак, если мы позвоним shortcut.add() непосредственно из тела цикла все анонимные функции, которые мы передаем, в конечном итоге увидят значение i то есть ток после завершения цикла, который всегда будет одинаковым (10).

Создание новой переменной в каждой итерации выглядит так, как будто она может работать, но не:

for (var i = 0; i <= 9; ++i) {
    var _i = i;  // Create new variable containing current value of 'i'.
    shortcut.add(i.toString(), function() {
        points = _i || -1;  // Won't work, '_i' is always 9.
        sec = 0;
    });
}

поскольку for тела цикла не имеют своей собственной области видимости в Javascript, _i заканчивается в объеме функции, так же, как iи будет получен таким же образом (его окончательное значение будет 9 вместо 10 так как ++i к нему не относится).

Итак, что нам действительно нужно, так это новая область в каждой итерации. Чтобы достичь этого, мы можем определить функцию внутри цикла и немедленно вызвать ее, передав ей текущее значение i:

var newScope = function(i) {
    // Here, the value of 'i' will be the one current when 'newScope' is called
    // and will not change, even if 'i' is captured by other functions.
};
newScope(i);  // Call function with current value of 'i'.

Наконец, мы можем сделать это без введения newScope имя, непосредственно применяя оператор вызова () к определению функции:

(function(i) {
    // Here, the value of 'i' will be the one current when this function is
    // called and will not change, even if 'i' is captured by other functions.
})(i);  // Call function with current value of 'i'.

Я надеюсь, что это правильно отвечает на ваши вопросы, не стесняйтесь оставлять дальнейшие комментарии, если это не так. Для получения дополнительной информации о замыканиях см. Закрытия в MDN.

Другие вопросы по тегам