最近用vue.js用的很爽,在全栈开发的路上一路狂奔,发现后台跟前台一起确实更有意义。
记录一个比较有意思的bug:
目标是对一个全局的paramList进行json格式化显示。代码借鉴了 http://tool.oschina.net/codeformat/json
for(var i = 0; i<_self.paramList.length; i++) {
id = "#" + _self.paramList[i];
console.log("___" + id) $(id).on("click", function () { console.log("**** id : " + id); _self.index = id.substring(1, id.length) console.log("new id :" + _self.index) var opt = { dom: "#preForParams" }; var jsonFormatter = new JsonFormater(opt); jsonFormatter.doFormat(js_source); $("#formParams").modal({ keyboard: true }); }); }
这段代码在Vue.ready方法里调用,发现最后永远显示的paramList的最后一个元素的json格式化<pre>。
在IDEA中有提示: mutable variable is accessible from closure.
1. 尝试初始化一个全局变量temp,在onclick方法里面使用_self.temp,发现_self.temp还是固定的值。
原因分析:在ready中代码已经执行完成,对那一时刻的状态而言,var i就是_self.paramList.length-1,所以每一个click时间注册都一list的最后一个数据为准,导致了bug产生 :(
2. 在stackoverflow发现解释:
The wrong way of using a closure inside a loop
for(var i = 0; i < 10; i++) { setTimeout(function() { console.log(i); }, 1000); }
具体参考 http://bonsaiden.github.io/JavaScript-Garden/#function.closures
这是javascript最重要的特性之一:闭包。
One of JavaScript's most powerful features is the availability of closures. With closures, scopes always keep access to the outer scope, in which they were defined. Since the only scoping that JavaScript has is function scope, all functions, by default, act as closures.
解决方案:
solution 1: with anonymous wrapper
for(var i = 0; i < 10; i++) { (function(e) { setTimeout(function() { console.log(e); }, 1000); })(i); }
solution 2: returning a function from a closure
for(var i = 0; i < 10; i++) { setTimeout((function(e) { return function() { console.log(e); } })(i), 1000) }
此方法体现了函数式编程的关键: 函数是一等公民。(意思是函数跟基本数据类型地位等同,computing 传入参数,得出结论。即只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,而且都有返回值。)
最终,采取了第一种solution,代码如下:
(function(e,v) { $(e).on("click", function () { console.log("**** id : " + e); _self.index = e.substring(1, e.length) console.log("new id :" + e) var opt = { dom: "#preForParams" }; var jsonFormatter = new JsonFormater(opt); jsonFormatter.doFormat(v); $("#formParams").modal({ keyboard: true }); }); })(id, js_source);
完美解决。