let解决for循环中的闭包

场景

  • 闭包产生

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

猜你喜欢

转载自blog.csdn.net/u011584949/article/details/83832507
今日推荐