Coffeescript类的行为不符合预期

Coffeescript Class not Behaving as Expected

本文关键字:不符合 Coffeescript      更新时间:2023-09-26

标题名称不好,抱歉。不知道该怎么总结

我试图使用OpenLayers地图API来打印一个带有许多标记的地图到一个页面。我有工作代码,但当我试图将其移动到一个单独的Coffeescript类时,它无声地失败了。下面的代码起作用了:

fromProjection = new OpenLayers.Projection("EPSG:4326") # Transform from WGS 1984
toProjection = new OpenLayers.Projection("EPSG:900913") # to Spherical Mercator Projection
mapnik = new OpenLayers.Layer.OSM()
markers = new OpenLayers.Layer.Markers("Markers")
map = new OpenLayers.Map("john-muir-trail-map")
markerCoordinates = -> $("'#john-muir-trail-data").data('markers').split('+')
paint = ->
  map.addLayer(mapnik)
  map.addLayer(markers)
  for pair in markerCoordinates()
    coords = pair.split(":")
    pos = new OpenLayers.LonLat(coords[1], coords[0]).transform( fromProjection, toProjection )
    markers.addMarker(new OpenLayers.Marker(pos))
    map.setCenter(pos, 8)

paint()

它依赖于存在的两个div(一个id为'john-muir-trail-map',另一个id为'john-muir-trail-data'和一些标记数据)。当上面的代码在我的主.coffee文件中时,它工作得非常好。

但是,当我试图通过将地图代码移动到一个单独的OpenLayerMap Coffeescript类来模块化事物时,没有错误引发,但它只是不起作用。这是我所做的。(我很确定我包括的东西是正确的。这个类可以从我的主文件中获得,它的方法和属性也是如此):

class OpenLayersMap
  constructor: (mapId) ->
    @mapId = mapId
  fromProjection: new OpenLayers.Projection("EPSG:4326") # Transform from WGS 1984
  toProjection: new OpenLayers.Projection("EPSG:900913") # to Spherical Mercator Projection
  mapnik: new OpenLayers.Layer.OSM()
  markers: new OpenLayers.Layer.Markers("Markers")
  map: new OpenLayers.Map("#{@mapId}-map")
  markerCoordinates: -> $("'##{@mapId}-data").data('markers').split('+')
  paint: ->
    @map.addLayer(@mapnik)
    @map.addLayer(@markers)
    for pair in @markerCoordinates()
      coords = pair.split(":")
      pos = new OpenLayers.LonLat(coords[1], coords[0]).transform( @fromProjection, @toProjection )
      @markers.addMarker(new OpenLayers.Marker(pos))
      @map.setCenter(pos, 8)
window.OpenLayersMap = OpenLayersMap

然后在前面的文件中像这样调用它:

map = new OpenLayersMap('john-muir-trail')
map.paint()

我不认为围绕投影等的OpenLayers细节是相关的。重要的是,mapId被正确地传递和使用,如果我在paint()函数中抛出一个调试器,调试器被击中,并且在那一点上可用的所有属性对我来说都很好。但是,没有映射正在被绘制。

我有Ruby背景,我想我对paint()函数的效果和副作用感到困惑。如果本质上是相同的行为,为什么在不同的文件中表现不同呢?

知道为什么这是失败的(默默地)吗?这让我有点抓狂。

我相信你在地图属性中使用@是导致问题的原因。不是访问OpenLayersMap的当前实例,而是调用OpenLayersMap上的静态属性mapId。例如:

map: new OpenLayers.Map("#{@mapId}-map")

将编译成:

OpenLayersMap.prototype.map = new OpenLayers.Map("" + OpenLayersMap.mapId + "-map");

你需要使map成为一个方法来访问构造函数中的@mapId集合。

map: -> new OpenLayers.Map("#{@mapId}-map")

我完全同意Kyle Needham的解释,但我想提出另一个解决方案。

要修复您的代码,只需将map赋值从类原型移动到它的构造函数:

class OpenLayersMap
  constructor: (mapId) ->
    @mapId = mapId
    @map = new OpenLayers.Map("#{@mapId}-map")

您应该考虑将fromProjection, toProjection, mapnikmarkers的定义也移动到构造函数中。

在您当前的实现中,OpenLayersMap的所有实例将具有相同的markers值,例如:

l1 = new OpenLayersMap 'l1'
l2 = new OpenLayersMap 'l2'
l1.markers is l2.markers # true, meaning they are the same object

因此,通过改变l1.markers,您不仅会影响OpenLayersMap类的所有现有实例,而且还会改变其原型。

这意味着通过在OpenLayersMap类的任何实例中改变这四个属性中的任何一个,您将对所有其他实例进行相同的更改。

如果所有这些类(Projection, LayerMarkers)是不可变的(即提供一堆帮助,但不保持状态),那么你的实现是正确的,但我怀疑有人会麻烦自己包装一堆无状态的帮助到类。

因此,考虑将代码更改为:
class OpenLayersMap
  constructor: (mapId) ->
    @mapId = mapId
    @map = new OpenLayers.Map "#{@mapId}-map"
    @fromProjection = new OpenLayers.Projection "EPSG:4326"
    @toProjection = new OpenLayers.Projection "EPSG:900913"
    @mapnik = new OpenLayers.Layer.OSM()
    @markers = new OpenLayers.Layer.Markers "Markers"

在这种情况下,OpenLayersMap的每个实例将有自己的fromProjection, toProjection, mapnikmarkers