最近用vue.js用的很爽,在全棧開發的路上一路狂奔,發現後臺跟前臺一塊兒確實更有意義。javascript
記錄一個比較有意思的bug:vue
目標是對一個全局的paramList進行json格式化顯示。代碼借鑑了 http://tool.oschina.net/codeformat/jsonjava
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>。git
在IDEA中有提示: mutable variable is accessible from closure.github
1. 嘗試初始化一個全局變量temp,在onclick方法裏面使用_self.temp,發現_self.temp仍是固定的值。編程
緣由分析:在ready中代碼已經執行完成,對那一時刻的狀態而言,var i就是_self.paramList.length-1,因此每個click時間註冊都一list的最後一個數據爲準,致使了bug產生 :(json
2. 在stackoverflow發現解釋:閉包
The wrong way of using a closure inside a loopapp
for(var i = 0; i < 10; i++) { setTimeout(function() { console.log(i); }, 1000); }
具體參考 http://bonsaiden.github.io/JavaScript-Garden/#function.closuresdom
這是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);
完美解決。