JS闭包 | 青训营笔记

39 阅读1分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天

闭包

我在写信息管理系统的前端页面,决定使用 jquery 来实现前后端分离,具体的方法是在前端 script 里面使用 ajax 来异步带着数据访问后端,然后根据后端返回的 json 来渲染前端的页面,至于我为什么会遇到闭包这个东西呢?听我慢慢道来 ...

当时写的代码是传给后端 token,然后后端根据 token 对应的用户的权限返回要加载的选项卡,后端功能很好实现,直接这么写就行了

token, isOk := c.GetPostForm("token")
if !isOk {
    c.JSON(200, map[string]interface{}{
        "msg": "fail",
    })
    return
}
if !service.CheckToken(&token) {
    c.JSON(200, map[string]interface{}{
        "msg": "fail",
    })
    return
}
if service.CheckRoot(&token) {
    c.JSON(200, map[string]interface{}{
        "msg": "ok",
        // TODO
    })
    return
}
infoBacks := []pojo.InfoBack{{
    ButtonId: "info",
    ObjUrl: "/info",
    ButtonName: "个人信息",
}, {
    ButtonId: "room",
    ObjUrl: "/room",
    ButtonName: "寝室",
}, {
    ButtonId: "clean",
    ObjUrl: "/clean",
    ButtonName: "卫生检查",
}, {
    ButtonId: "break",
    ObjUrl: "/break",
    ButtonName: "报修",
}, {
    ButtonId: "lost",
    ObjUrl: "/lost",
    ButtonName: "失物招领",
},
                            }
c.JSON(200, map[string]interface{}{
    "msg": "ok",
    "infos": infoBacks,
})

实现接口之后我就把视线转到前端了,先 F12 里的 console 里测试了下,可以接收到 json 数据,然后就开始写 js 了,大致思路的根据传回的数据,遍历所有元素然后创建 li 标签加按钮,最后把创建出来的按钮绑定上 click 事件的函数

初版代码是这样的

<script charset="utf-8">
	$(function() {
		$("#quit").click(function() {
			var token = localStorage.getItem("token");
			localStorage.removeItem("token");
			var tks={"token":token}
			$.post(
				"/quit",
				tks,
				function() {
					location.assign("/login");
				}
			);
		});
		var token = localStorage.getItem("token");
		$.post(
			"/index",
			{"token": token},
			function(data) {
				var indexs = data
				for(var i = 0; i < data.infos.length; i++) {
					$("#menu").append("<li class=\"nav-item\"><button class=\"my-2 btn btn-secondary btn-block w-100\" type=\"button\" id=\"" + data.infos[i].button_id + "\">" + data.infos[i].button_name + "</button></li>");
					$("#" + data.infos[i].button_id).click(function() {
						$.get(
							indexs.infos[i].obj_url,
							function() {
								console.log("6")
							}
						)
					});
				}
				// TODO
			}
		);
	});
</script>

既然是初版代码,那必然是有问题的,运行结果是标签渲染出来了,但是按钮按下去无事发生,console 里没显示 6,后端的日志也没有显示 404 的 get 请求(那些端口我都没写好

可喜可贺的是我在 console 里仔细看了下发现了在按下按钮之后他报错了,说indexs.infos[i] is undefined ,然后我大概知道了是怎么一回事,绑定函数的过程不包括执行,所以再次运行的时候它是独立出来运行的,这时候 i 就不见了,所以就报错了

那么怎么解决这个问题呢?凭我的经验肯定不能解决这种问题,借助了强大的搜索引擎,我找到了和我遇到类似问题的人 🔗

下面是能够 work 的代码

<script>
function(data) {
	var indexs = data;
	for(var i = 0; i < data.infos.length; i++) {
		$("#menu").append("<li class=\"nav-item\"><button class=\"my-2 btn btn-secondary btn-block w-100\" type=\"button\" id=\"" + data.infos[i].button_id + "\">" + data.infos[i].button_name + "</button></li>");
		(function(i) {
		$("#" + data.infos[i].button_id).click(function() {
			$.get(
				indexs.infos[i].obj_url,
				function() {
					console.log("6")
				}
			)
		});})(i)
	}
}
</script>

一个人同时写前后端真的挺累的,不过成就感倒是有的,web 也就这回事