2016-07-29 204 views
0

我一直在寻找一些JavaScript代码来创建一个计算器应用程序。这很简单,但是让我困惑的是当函数返回一个函数时。函数返回一个函数(JavaScript)的

与下面的代码,我明白了计算器的每个按钮需要一个事件侦听器来使用“点击”,在其功能取决于被点击了哪个按钮调用。 addValue(i)函数在单击按钮时将按钮值添加到结果字段。下面的函数有一个返回函数的函数。没有函数调用,结果返回“789 + 456-123/0. = x”

有些人可以解释为什么addValue(i)函数需要返回函数才能使此函数正常工作。要做到这一点

for (var i=0; i<buttons.length; i++) { 
    if(buttons[i] === "="){ 
     buttons[i].addEventListener("click", calculate(i)); 
    } else { 
     buttons[i].addEventListener("click", addValue(i)); 
    } 
} 

function addValue(i) { 
    return function() { 
     if(buttons[i].innerHTML === "÷") { 
      result.innerHTML += "/"; 
     } else if (buttons[i] === "x") { 
      result.innerHTML += "*"; 
     } else { 
      result.innerHTML += buttons[i].innerHTML; 
     } 
    } 
}; 
+4

可能的重复[JavaScript关闭如何工作?](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Marty

回答

-1

方式一:

for (var i=0; i<buttons.length; i++) { 
    (function(i) { 
     if(buttons[i] === "="){ 
      buttons[i].addEventListener("click", function() { calculate(i) }); 
     } else { 
      buttons[i].addEventListener("click", function() { addValue(i) }); 
     } 
    })(i); 
} 

你可以阅读更多关于JavaScript的关闭here

所以从我收集下面马蒂(和重新阅读您的问题),你想知道为什么你需要返回一个函数(或类似)。 addEventListener需要一个在发生点击事件时被调用的函数。因为你没有直接调用函数(也就是运行它),所以你没有任何发言权来传递参数。在这种情况下,唯一传递的参数是一个事件对象,包含有关点击发生的位置,绑定到的元素等的信息。您必须将其包含在另一个函数中才能传递值i到您必须运行的最终功能。 (我已经在上面显示了另一个例子)。

+2

请解释downvote吗? – FrankerZ

+0

你的“这里有这个代码”的例子是OP的第一个地方尝试和理解的另一个排列...... – Marty

+0

我给了他代码,并给了他一个可以进一步解释闭包的链接。这是一个什么问题? – FrankerZ

1

在本例中,我假设该网页是一个计算器,类似于:

|---------------| 
|    | 
|---------------| 
| 1 | 2 | 3 | * | 
|---|---|---|---| 
| 4 | 5 | 6 |/| 
|---|---|---|---| 
| 7 | 8 | 9 | = | 
|---------------| 

在这种情况下,按钮buttons[i]是计算器按钮中的一个; | 1 || 5 |等按钮的实际数量是它的指数,所以buttons[2]| 2 |buttons[7]| 7 |,等我猜其他值,像buttons[0]buttons[10],是经营者的按钮(| = || * ||/|)。

现在,当对这些按钮中的一个,在按钮上的字符,这是该按钮的innerHtml,被添加到用户点击计算器的result(通过将其添加到结果的innerHTML),这仅仅是一个显示操作。所以,如果我点击| 3 |,然后| * |,然后| 5 |,计算器看起来像

|---------------| 
|   3*5 | 
|---------------| 
| 1 | 2 | 3 | * | 
|---|---|---|---| 
| 4 | 5 | 6 |/| 
|---|---|---|---| 
| 7 | 8 | 9 | = | 
|---------------| 

下面是其中addEventListener用武之地。当你调用element.addEventListener("click", func),只要单击elementfunc将被调用。因此,要单击时按钮添加到结果,你可以这样做:

buttons[i].addEventListener("click", addButtonValueToResult); 

其中addButtonValueToResult是按钮的值添加到结果的功能。

的问题是,不同的按钮有不同的价值观,所以像这样的功能不会为所有这些工作。因此,addButtonValueToResult不能是一个简单的功能;每个按钮都需要自己的功能。这样的一个解决方案是沟for循环,只是这样做:

buttons[1].addEventListener("click", add1ToResult); 
buttons[2].addEventListener("click", add2ToResult); 
buttons[1].addEventListener("click", add3ToResult); 
... 

再有这样的功能:

function add1ToResult() { 
    result.innerHTML += "1" 
} 

但是这需要花费很多不必要的工作,因为你需要添加功能对于每个数字按钮(| 1 || 9 |)以及操作员按钮(| = |,|/|| * |),它们只是将innerHtml s添加到结果中。而且,按钮的索引已经分配给一个变量i,整个按钮可以用该索引与buttons[i]引用。难道你不能让程序自动为每个按钮创建一个函数:当给定按钮的索引i时,获取按钮(通过buttons[i])并将该按钮的值添加到结果中?

那么这正是这个程序所做的:addValue(i)不只是添加按钮的内部值本身;它返回另一个功能,也有一些特殊按钮的测试用例,添加按钮的内部值。看看这个代码:

function addValue(i) { 
    return function() { 
     if(buttons[i].innerHTML === "÷") { 
      result.innerHTML += "/"; 
     } else if (buttons[i] === "x") { 
      result.innerHTML += "*"; 
     } else { 
      result.innerHTML += buttons[i].innerHTML; 
     } 
    } 
}; 

说你叫addValue(3);这将返回一个函数,将result中的数字3添加到结果中。如果您拨打addValue(9);这将返回一个函数,将9添加到结果中,位于result。您可以调用函数addValue返回,并通过(addValue(digit)())实际向结果添加数字。但addEventListener不会计算评估结果;它需要一个函数,它将在稍后点击该按钮时调用。