let解決for迴圈中的閉包
阿新 • • 發佈:2018-12-20
場景
-
閉包產生
- 內部函式依賴了外部作用域變數,即內部持有外部引用不釋放(延續了引用變數的生命週期,延壽)
- 變數的本質其實就是一個佔位符,其值才是真正操作物件
- 值可以是各語言的標量,也可以是記憶體地址(即通俗的引用型別)
-
var VS let
- let 塊級用域(ES5之前的js不存在塊級作用域)
- 在一個塊級作用域內,let 宣告 的變數只會在該區域記憶體續
- var 不存在塊的問題,可以在塊外繼續生活
-
與for的關係
- var 初始變數在for迴圈體內,是覆蓋式的,用C的話來講是共用體,即共用同一記憶體地址
- let初始變數在每一次for迴圈中,都是一個獨立的變數,擁有自己獨立的記憶體地址。
-
函式體內部引用了內部不存在的變數,會尋找上層作用域內的同名變數
-
let + for + fn
- for語句塊內的函式引用了該層let宣告變數
- 函式引用了外部作用域 變數不會主動釋放,即若該函式被呼叫該變數會存活於記憶體中。
-
小結
- for迴圈體內定義fn ,若函式體內用了for塊var變數,在for語句外呼叫該函式,該函式採用的var值是迴圈結束後的var值
- 而塊內用let變數,與之同級的函式體用了該let變數,之後呼叫函式,函式使用的是定義時塊內的let變數值。
- 關鍵是否使用同一值(或址)
程式碼
js生成高德地圖示記
buildMarkers() { // 初始化標記陣列 this.markers = []; var image = ROAST_CONFIG.APP_URL + "/storage/img/coffee-marker.png"; // 自定義點標記 var icon = new AMap.Icon({ image: image, imageSize: new AMap.Size(19, 33) }); for (var i = 0; i < this.cafes.length; i++) { // 為每個咖啡店建立點標記並設定經緯度 var marker = new AMap.Marker({ position: new AMap.LngLat( parseFloat(this.cafes[i].longitude), parseFloat(this.cafes[i].latitude) ), title: this.cafes[i].location_name, icon: icon, // 標記額外資料,方便過濾 extData: { cafe: this.cafes[i] }, map: this.map, clickable: true }); // 自定義窗體資訊,必須使用let生成塊級作用域,此變數在for語句塊中每一次迴圈中都是一個新變數,準確的來說是一個新的記憶體地址,產生了新副本執行時就固定了下來 // 理由mark點選事件處理器依賴了該變數。而在js中閉包依賴,會尋找上級作用域(如果上級有作用域的話)內的值的引用,從而不會釋放 // 用var的話,由於在for區間內不存在塊作用域,其infoWindow值是for迴圈結束後的值 let infoWindow = new AMap.InfoWindow({ content: this.cafes[i].name +'_'+ this.cafes[i].location_name }); // 繫結點選事件到點標記物件,點選開啟上面建立的資訊窗體 marker.on("click", function() { infoWindow.open(this.getMap(), this.getPosition()); }); this.infoWindows.push(infoWindow); // 將標記放到陣列中 this.markers.push(marker); } // 將所有的標記顯示到地圖 this.map.add(this.markers); },