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



我的简单测试程序正确地加减数字。但是,我想把我的全局变量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>

实现这一点的方法是将所有代码从全局范围中取出,无论如何都应该努力做到这一点。这通常是通过将所有代码包装在立即调用函数表达式中来完成的。

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

最后,除非您有一个特定的用例,否则请避免像以下这样的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>

您可以将所有变量和函数移动到IIFE(立即调用的函数表达式)的内部。

'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;
}();
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>

最新更新