frond-end

理解Closure–记一次JS代码Debug过程

内容概要: javascript closure

刚入门前端开发, 写一个页面时遇到一次 Closure 导致的问题, 花了一些功夫才解决, 这里记录下。

问题描述:

JS 代码根据后台返回的数据列表来渲染form 呈现, 每一条Item 对应一个form , form 里面有link , 绑定了click 事件, 事件响应函数要接收Item 里面的数据:

function displayDevice(data) {
    devicenum = data.length;
    var devices = $('#edit_devices');
 
 
    for (i = 0; i < devicenum; i++) {
        var id = i + 1;
        var devid = "device" + id;
        var deviceinfo = data[i];
 
        devices.append('<div id ="' + devid + '">' +
            '<form>' +
            '<label for="orig_deviceid" class = "control-label col-md-2" >DeviceSN</label>' +
            '<input type="text" id="orig_deviceid"  class = "form-control" value="' + deviceinfo.DeviceSN + '"  readonly >' +
 
            '<label for="orig_devicetype" class = "control-label col-md-2" >DeviceType</label>' +
            '<select class = "form-control" id="orig_devicetype" > ' +
            '<option value="ASIA">ASIA</option>' +
            '<option value="ABIK">ABIK</option>' +
            '<option value="ASIK">ASIK</option>' +
            '<option value="ABIL">ABIL</option>' +
            '<option value="Airframe">Airframe</option>' +
            '<option value="CloudCU">CloudCU</option>' +
            '</select>' +
 
            '<label for="orig_location" class = "control-label col-md-2" >DeviceLocation</label>' +
            '<input type="text" id="orig_location" class = "form-control" value = "' + deviceinfo.Location + '" >' +
 
            '<label for="orig_devicehwversion" class = "control-label col-md-2" >HWVersion</label>' +
            '<input type="text" id="orig_devicehwversion" class = "form-control" value= "' + deviceinfo.HWVersion + '" >' +
 
            '<label for="orig_deviceip" class = "control-label col-md-2" >IP</label>' +
            '<input type="text" id="orig_deviceip" class = "form-control" value = "' + deviceinfo.IP + '" > ' +
 
            '<label for="orig_deviceremark" class = "control-label col-md-2" >Remark</label>' +
            '<textarea id="orig_deviceremark" rows="5" class = "form-control" maxlength="150" >' + deviceinfo.Remark + '</textarea > ' +
 
            '<a href="javascript:void(0);"  class="col-lg-offset-1 col-lg-2 " id="' + devid +'"  >Delete this device</a>' +
 
            '</form>' +
 
            '<hr />' +
 
            '<div/>');
 
        var select = $('#' + devid + ' #orig_devicetype').val(deviceinfo.DeviceType);
 
            //pay attention to Closure here
            $('a#' + devid).click(  function () 	
                rmvDevice(devid, deviceinfo.DeviceSN);
        );    
 
    }
 
}

注意最后注册click 事件的代码, 里面使用了和具体的条目相关的变量, 在循环中会改变的。

然后在调试时就出现比较诡异的现象, 如果有5个item , 则5个form 里面的 < a > 元素触发click动作时, 调用revDevice 函数时传入的数据永远是最后一个item 对应的数据

这里不得不感叹Chrome 调试工具很强大, 在审查element 可以看到对应元素的event listener , 在里面可以看到5个 < a > 元素的click 事件处理函数的Closure 都是一样的, 可以直接定位到是closure 相关的问题。
Closure 相关的内容,材料网上有很多, 这里就不涉及了。

closure


JS 为html 元素注册事件时, 函数作为一个参数在传递, 而不会立即执行, 对应事件才会触发函数执行JS 中函数作为参数或者返回值时, 是作为Closure的, 会保存相关的参数和变量在Closure 中。

传递函数( Closure ) 时千万要注意不要引用循环变量,或者后续会发生变化的变量。如果一定要引用会变化的量, 则应该再创建一个函数, 用该函数的参数绑定变量当前的值,确保传递到函数参数的值不变。

最后代码为再创建一个函数, 用该函数参数绑定变量当前的值, 问题解决:

//pay attention to Closure here
$('a#' + devid).click((function (id, sn) {	
	return function () {
		rmvDevice(id, sn);
	}
})(devid, deviceinfo.DeviceSN)
);    


javascript closure 同时发布于CSDN:
https://blog.csdn.net/xiaoyaohuqijun/article/details/79506250

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top