场景
-
闭包产生
- 内部函数依赖了外部作用域变量,即内部持有外部引用不释放(延续了引用变量的生命周期,延寿)
- 变量的本质其实就是一个占位符,其值才是真正操作对象
- 值可以是各语言的标量,也可以是内存地址(即通俗的引用类型)
-
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);
},