【问题标题】:Scoping issues in javascript classesjavascript 类中的范围问题
【发布时间】:2011-04-18 09:02:43
【问题描述】:

我的经典程序员爱上了 OO 的公共/私有范式,我发现很难放弃。这导致我遇到了一个希望您能帮助我解决的问题。

我有一个名为 map 的单例对象。只可以有一个人。该地图包含名为 Star 的对象(这是一个游戏)。星星看起来像这样:

var Star = function(id, x, y) {
    this.id_ = parseInt(id);
    this.x_ = parseInt(x);
    this.y_ = parseInt(y);
};

实际上还有更多的参数和属性。这只是一个例子。

地图是这样定义的:

var map = (function() {
    // public interface
    return {
        init: function() {
            getStars();         
        },
        stars: {} // works but publicly accessible
    };

    var stars = new Array(); // fail

    function getStars() {
        $.getJSON("ps.php?jsoncallback=?", addStars);
    }

    function addStars(data) {
        for (var x=0, xx=data.stars.length; x<xx; x++) {
            map.stars[data.stars[x].id] = new Star(
                data.stars[x].id,
                data.stars[x].xpos, 
                data.stars[x].ypos
            );
        }
    }
})();

我认为由于addStars 的作用域是$.getJSON 的回调函数,它不能将新创建的星添加到星的私有变量中(FireBug 说它是未定义的,jQuery 在之后调用abort它试图添加它)。但是,如果我将星星设为公开可见的对象,那么它确实可以工作,但是从界面可以看到星星,这不是我想要的。

我怎样才能保持星星的私密性并使其可以从 JSON 回调中访问?

【问题讨论】:

  • @SLaks: 或者可能是Number(x) 甚至+x,因为它们没有以 8 为基数的解析。 IMO,parseInt() 仅在文本可能跟在数字后面时才需要。
  • 但是由于从 JSON 返回的所有项目都是字符串,因此肯定需要将那些是数字的项目从字符串转换为数字,这就是 parseInt 所做的。 Number 是否提供比 parseInt 更好的性能?

标签: javascript class callback scope


【解决方案1】:

您可以引用stars 而不在其前面添加map。

var map = (function() { 

    var stars = new Array(); 

    function getStars() { 
        $.getJSON("ps.php?jsoncallback=?", addStars); 
    } 

    function addStars(data) { 
        for (var x=0, xx=data.stars.length; x<xx; x++) { 
            stars[data.stars[x].id] = new Star( 
                data.stars[x].id, 
                data.stars[x].xpos,  
                data.stars[x].ypos 
            ); 
        } 
    } 

    // this should be at the bottom.

    // public interface 
    return { 
        init: function() { 
            getStars();          
        }
    }; 

})(); 

在与stars 相同的范围上下文中定义addStars 会创建一个闭包,使stars 在函数被调用时可用。

【讨论】:

  • 我很确定我试过这个,但检查行星在 Firebug 中仍然显示未定义。此外,如果我使用 Array,则 stars 的长度为 36301(所有对象中所有字段的总和),而 Object 的使用允许我单独使用每个 Star。
【解决方案2】:

您在返回后定义了星星。它永远不会被创建,它肯定是未定义的。

[See is in action]

var map = (function() {     

    var stars = new Array(); // define before return!

    function getStars() {
        $.getJSON("ps.php?jsoncallback=?", addStars);
    }

    function addStars(data) {
        for (var x=0, xx=data.stars.length; x<xx; x++) {
            stars[data.stars[x].id] = new Star( // use private stars
                data.stars[x].id,
                data.stars[x].xpos, 
                data.stars[x].ypos
            );
        }
    }

    // public interface
    return {
        init: function() {
            getStars();         
        }
    };
})();​

【讨论】:

    【解决方案3】:

    虽然stars 可以被认为是一个私有成员,但它实际上只存在于定义map 的自调用函数的范围内。因此,您无法通过map.stars 访问它,但是您可以在回调函数中简单地访问stars。

    var map = (function() {
    
        var stars = [];
    
        function getStars() {
            $.getJSON("ps.php?jsoncallback=?", function(data) {
                for (var x=0, xx=data.stars.length; x<xx; x++) {
                    stars[data.stars[x].id] = new Star(
                        data.stars[x].id,
                        data.stars[x].xpos, 
                        data.stars[x].ypos
                    );
                }
            });
        }
    
        // public interface
        return {
            init: function() {
                getStars();         
            }
        };
    })();
    

    【讨论】:

      猜你喜欢
      • 2010-09-24
      • 2011-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-24
      相关资源
      最近更新 更多