JavaScript的闭包案例---1

目录

背景

  闭包是JavaScript中的一个重要概念。
  JavaScript采用词法作用域,函数的执行依赖于变量作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的。函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这就是闭包的特性。

实际场景

  在完成一个小demo时,正巧遇到了这个问题。先说一下这个demo要实现的基本功能吧。要求能让用户输入城市名称和对应的空气质量指数(输入的名称和指数都要做表单验证),输入完成后点击确定,将合法的数据显示在本页的列表中,可以增加多条记录。并且已添加的数据可以逐条删除。这里仅从功能展示,没有使用css美化页面:

  在做删除功能时,按着想法先写了一遍,进行实际测试时候发现一个问题:对于最后一列的删除按钮,无论点击哪一个,都是列表中最后一条数据被删除了。
  开始代码是这样写的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
* 渲染aqi-table表格
*/

function renderAqiList() {
var aqiTable = document.getElementById("aqi-table");
aqiTable.innerHTML = "";
var t_row = document.createElement("tr");
var t_city = document.createElement("td");
var t_score = document.createElement("td");
var t_oper = document.createElement("td");
t_city.innerHTML = "城市";
t_score.innerHTML = "空气质量";
t_oper.innerHTML = "操作";
t_row.appendChild(t_city);
t_row.appendChild(t_score);
t_row.appendChild(t_oper);
aqiTable.appendChild(t_row);
//遍历对象中所有属性渲染表格
for (var name in aqiData){
var newLi = document.createElement("tr");
var cityName = document.createElement("td");
var score = document.createElement("td");
var oper = document.createElement("td");
var delBtn = document.createElement("button");
cityName.innerHTML = name;
score.innerHTML = aqiData[name];
delBtn.innerHTML = "删除";
delBtn.setAttribute("city", name);
delBtn.onclick = function (){
delBtnHandle(name);
};
oper.appendChild(delBtn);
newLi.appendChild(cityName);
newLi.appendChild(score);
newLi.appendChild(oper);
aqiTable.appendChild(newLi);
}
return;
}

  其中最关键的是给删除按钮绑定事件:

1
2
3
delBtn.onclick = function (){
delBtnHandle(name);
};

  这种做法想当然的认为,只要发生click事件时候,调用delBtnHandle()函数,并把要删除城市对应的name参数传递过去就好了,但在js中并不是这么执行的,这就要考虑到闭包的概念了。换做如下写法,问题就得到了解决。

1
2
3
4
5
6
7
/*难点:js闭包的运用,防止出现以下错误:for循环时动态绑定,使得onclick
事件需要的name只能取到最后一个值而不是每一次遍历*/

delBtn.onclick = function (asd) {
return function (){
delBtnHandle(asd);
   }
}(name);