Проблемы с областями видимости в классах JavaScript - PullRequest
2 голосов
/ 28 сентября 2010

Классический программист во мне влюблен в публичную / частную парадигму ОО, и мне очень трудно сдаться.Это заставило меня столкнуться с проблемой, с которой я надеялся, что вы мне поможете.

У меня есть одноэлементный объект с именем map.Там может быть только один.Эта карта содержит объекты под названием Звезда (это игра).Звезда выглядит так:

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?

Ответы [ 3 ]

2 голосов
/ 28 сентября 2010

Вы определили звезды после возвращения. Он никогда не создается , уверен, он не будет определен.

[ См. В действии ]

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();         
        }
    };
})();​
2 голосов
/ 28 сентября 2010

Вы можете ссылаться на 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();          
        }
    }; 

})(); 

определение addStars в том же контексте области, что и stars, создает замыкание, делая stars доступным при каждом вызове функции.

0 голосов
/ 28 сентября 2010

Хотя 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();         
        }
    };
})();
...