2

我正在使用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。

关于如何实现这一点的任何想法?谢谢!

4

1 回答 1

3

带有闭包的循环应该可以解决问题:

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 上的闭包

于 2012-06-26T13:03:19.073 回答