如何在闭包内将变量从全局移动到局部

时间:2017-11-09 21:48:39

标签: javascript closures

我的简单测试程序正确地添加和减去数字。但是,我想将我的全局变量counter转换为局部变量。我无法从逻辑上看到如何执行此操作并仍然保持程序运行。有没有办法定位counter,以便只能通过addNumbersubtractNumber关闭来访问它?非常感谢!

'use strict';
	
var counter;
counter = 0;
	
document.getElementsByClassName('box')[0].addEventListener('click', addNumber);
document.getElementsByClassName('box')[1].addEventListener('click', subtractNumber);
document.getElementsByClassName('box_answer')[0].textContent = 'The answer is ' +counter;

function calculateNumber(x) {
  counter += x;
  displayNumber();
}
	
function displayNumber() {
  document.getElementsByClassName('box_answer')[0].textContent = 'The answer is ' +counter;
}
	
function addNumber() {
  calculateNumber(1);		
}
	
function subtractNumber() {
  calculateNumber(-1);	
}
body {
  margin: 0;
  padding: 0;
  font-size: 2rem;
  font-family: sans-serif;
}
	
.box {
  margin-bottom: 20px;
  padding: 10px;
  color: white;
  background-color: blue;
}

.box_answer {
  padding: 10px;
  background-color: orange;
}
<div class="box">addNumber</div>
<div class="box">subtractNumber</div>
<div class="box_answer"></div>

2 个答案:

答案 0 :(得分:2)

这样做的方法是获取所有代码并将其从全局范围中删除,无论如何,您应始终努力做到这一点。这通常通过将所有代码包装在立即调用的函数表达式中来完成。

此外,您不需要单独的加法和减法功能。只需让每个click事件处理程序调用一个函数,并将值传递给该函数。

最后,除非您有特定用例,否则请避免使用DOM API调用:

  • .getElementsByName()
  • .getElementsByTagName()
  • .getElementsByClassName()

因为它们都返回“实时”节点列表,这会导致每次在代码中引用节点列表时重新扫描整个DOM以查找匹配元素。这可能导致戏剧性的表现。相反,使用更现代的:

  • .querySelector()
  • .querySelectorAll()

,当然还有:

  • .getElementById()

这三个API将处理您的大多数DOM查询需求。

(function(){
  'use strict';
	
  // .getElementsByClassName returns a "live" node list, which is not recommended
  // for most use cases because it requires re-scanning the DOM every time the node
  // list is used. querySelector() and .querySelectorAll() are the modern  successors 
  // to that.
  var answer = document.querySelector('.box_answer'); 
  
  // Find box by its unique class (or id) so that you don't scan the entire DOM only to
  // throw away all found elements but the one you want:
  document.querySelector('.box.add').addEventListener('click', function() { doMath(1); });
  document.querySelector('.box.subtract').addEventListener('click', function() { doMath(-1); });

  var counter = 0;

  function doMath(x) {
    counter += x;
    displayNumber();
  }
	
  function displayNumber() {
    answer.textContent = 'The answer is ' + counter;
  }
	
})();
body {
  margin: 0;
  padding: 0;
  font-size: 2rem;
  font-family: sans-serif;
}
	
.box {
  margin-bottom: 20px;
  padding: 10px;
  color: white;
  background-color: blue;
  cursor:pointer;  /* Change pointer to let user know they can click */
  
  /* Prevent text in element from being selected. Helps when lots of clicking happens. */
  user-select:none;   
}

.box_answer {
  padding: 10px;
  background-color: orange;
}
<div class="box add">addNumber</div>
 <!-- Give each box a different class (or id) to differentiate one from the other. -->
<div class="box subtract">subtractNumber</div>
<div class="box_answer">The answer is:</div>

答案 1 :(得分:2)

您可以移动IIFE (immediately-invoked function expression)内的所有变量和函数。

&#13;
&#13;
'use strict';
	
void function () {
    function calculateNumber(x) {
        counter += x;
        displayNumber();
    }
	
    function displayNumber() {
        document.getElementsByClassName('box_answer')[0].textContent = 'The answer is ' +counter;
    }
	
    function addNumber() {
        calculateNumber(1);		
    }
	
    function subtractNumber() {
        calculateNumber(-1);	
    }

    var counter = 0;

    document.getElementsByClassName('box')[0].addEventListener('click', addNumber);
    document.getElementsByClassName('box')[1].addEventListener('click', subtractNumber);
    document.getElementsByClassName('box_answer')[0].textContent = 'The answer is ' + counter;
}();
&#13;
body { margin: 0; padding: 0; font-size: 2rem; font-family: sans-serif; }
.box { margin-bottom: 20px; padding: 10px; color: white; background-color: blue; }
.box_answer { padding: 10px; background-color: orange; }
&#13;
<div class="box">addNumber</div>
<div class="box">subtractNumber</div>
<div class="box_answer"></div>
&#13;
&#13;
&#13;