【问题标题】:Variable set in constructor is undefined in different method构造函数中设置的变量在不同的方法中未定义
【发布时间】:2015-04-24 15:36:59
【问题描述】:

我正在使用 Google 地图计算票价的 CoffeeScript 库。

当像这样初始化地图时:

var viewport = document.getElementById('viewport'),
    options = {
        center: new google.maps.LatLng(-34.397, 150.644),
        zoom: 8
    };

google.maps.event.addDomListener(window, 'load', function()
{
    var map = new google.maps.Map(viewport, options);
});

它按预期加载。

但是当我使用我的库初始化它时:

var viewport = document.getElementById('viewport'),
    options = {
        center: new google.maps.LatLng(-34.397, 150.644),
        zoom: 8
    },

    map = new FareJS.Map(viewport, options);

视口保持灰色,移动地图会得到TypeError: a is undefined

经过一番研究,我发现Map类中initializeMap方法中@opt的值是未定义的。我觉得很奇怪,因为我在构造函数中设置了它。更奇怪的是@viewport 不是未定义...只是@opt

有问题的班级是

class Map
    constructor: (@viewport, @opt) ->
        if not window.hasOwnProperty('google')
            throw "Google Maps API could not be found, are you sure you installed it?"

        @loadMapOnLoad()

    initializeMap: () ->
        @map = new google.maps.Map(@viewport, @opt)
        return

    loadMapOnLoad: () ->
        google.maps.event.addDomListener(window, 'load', @initializeMap)
        return

编译后如下所示:

var Map;

Map = (function() {
    function Map(viewport, opt) {
        this.viewport = viewport;
        this.opt = opt;
        if (!window.hasOwnProperty('google')) {
            throw "Google Maps API could not be found, are you sure you installed it?";
        } 
        this.loadMapOnLoad();
    }

    Map.prototype.initializeMap = function() {
        this.map = new google.maps.Map(this.viewport, this.opt);
    };

    Map.prototype.loadMapOnLoad = function() {
        google.maps.event.addDomListener(window, 'load', this.initializeMap);
    };

    return Map;

})();

为什么会这样,我该如何解决?

【问题讨论】:

    标签: coffeescript


    【解决方案1】:

    问题是initializeMap 将在您的类/对象的上下文之外执行。 this 不会在 initializeMap 中引用您的类实例。您必须执行以下操作之一:

    # explicitly bind to @
    # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
    google.maps.event.addDomListener window, 'load', @initializeMap.bind @
    
    # preserve context with => and call regularly 
    google.maps.event.addDomListener window, 'load', => @initializeMap()
    
    # declare method with bound context, so it doesn't matter how you call it
    # (resulting behaviour could be considered somewhat unidiomatic for JS, caveat emptor)
    class Map
      initializeMap: =>
        ..
    

    【讨论】:

    • 使用bind 比第二种方法更有效并产生更简洁的代码。到目前为止,我从未使用过.bind。非常感谢您的帮助!
    • 我认为这值得商榷。 bind 可能有点笨拙... @foo.bar.baz.bind @foo.bar :)
    • Uhhhmmm...是的...好点。我想这取决于项目,我会说较小的项目可以侥幸。
    • initializeMap: () => ...class 中是另一种选择,如果您一直希望绑定initializeMap
    • 不,m: => ... 创建一个绑定(到实例)方法,@m: => ... 将是一个绑定(到类)类方法:jsfiddle.net/ambiguous/trqrbt21
    猜你喜欢
    • 1970-01-01
    • 2017-05-28
    • 2023-03-21
    • 2018-09-01
    • 2017-07-16
    • 1970-01-01
    • 2021-01-19
    • 2012-11-10
    • 2011-06-06
    相关资源
    最近更新 更多