Назначение переменных класса обратного вызова AJAX и Javascript - PullRequest
0 голосов
/ 26 марта 2010

Я пытаюсь создать небольшой класс javascript для геокодирования адресов через API Карт Google. Я изучаю Javascript и AJAX и до сих пор не могу понять, как я могу инициализировать переменные класса с помощью обратного вызова:

    // Here is the Location class, it takes an address and 
    // initialize a GClientGeocoder. this.coord[] is where we'll store lat/lng
    function Location(address) {
        this.geo = new GClientGeocoder();
        this.address = address;
        this.coord = [];                        
    }

    // This is the geoCode function, it geocodes object.address and 
    // need a callback to handle the response from Google
    Location.prototype.geoCode = function(geoCallback) { 
        this.geo.getLocations(this.address, geoCallback); 
    }

    // Here we go: the callback. 
    // I made it a member of the class so it would be able 
    // to handle class variable like coord[]. Obviously it don't work.
    Location.prototype.geoCallback = function(result) {
        this.coord[0] = result.Placemark[0].Point.coordinates[1];
        this.coord[1] = result.Placemark[0].Point.coordinates[0];
        window.alert("Callback lat: " + this.coord[0] + "; lon: " + this.coord[1]);
    }

    // Main
    function initialize() {
        var Place =  new Location("Tokyo, Japan");
        Place.geoCode(Place.geoCallback);
        window.alert("Main lat: " + Place.coord[0] + " lon: " + Place.coord[1]);
    }

    google.setOnLoadCallback(initialize);

Спасибо за помощь!

EDIT

Спасибо TJ за ваш ответ. Я прочитал твой пример и твой пост - все становится намного яснее. Но у меня все еще есть проблема. Посмотрите:

function bind(context, func) {
    return function() {
        return func.apply(context, arguments);
    }
}
function Location(address) {
    this.geo = new GClientGeocoder();
    this.address = address;
    this.coord = [];                        
}

Location.prototype.geoCode = function(callback) { 
    this.geo.getLocations(this.address, callback); 
}

Location.prototype.geoCallback = function(result) {
    this.coord[0] = result.Placemark[0].Point.coordinates[1];
    this.coord[1] = result.Placemark[0].Point.coordinates[0];
    // This alert is working properly, printing the right coordinates
    window.alert("I am in geoCallback() lat: " + this.coord[0] + "; lon: " + this.coord[1]);
}

function initialize() {
    var Place =  new Location("Tokyo, Japan");
    Place.geoCode(bind(Place, Place.geoCallback));
    window.alert("I am in initialize() lat: " + Place.coord[0] + "; lon: " + Place.coord[1]);
}

Почему предупреждение в initialize () появляется перед предупреждением в geoCallback (), выводя неопределенное / неопределенное значение

1 Ответ

1 голос
/ 26 марта 2010

Что вам нужно сделать, это убедиться, что this установлен правильно в обратном вызове. Это иногда называют «обязательным». Для этого Prototype предоставляет Function#bind, но сделать это достаточно просто, если вы не используете Prototype & mdash; Определите функцию, которая будет выполнять связывание для вас:

function bind(context, func) {
    return function() {
        return func.apply(context, arguments);
    }
}

, а затем используйте его в вашем initialize звонке:

function initialize() {
    var Place =  new Location("Tokyo, Japan");
    Place.geoCode(bind(Place, Place.geoCallback)); // <= Change is here
    window.alert("Main lat: " + Place.coord[0] + " lon: " + Place.coord[1]);
}

(хотя я думаю, что я бы предложил немного изменить рефакторинг, чтобы вызывающий geoCode не должен был обеспечивать обратный вызов на этом уровне.)

То, что bind выше делает, - это создает замыкание (функцию), которое при вызове оборачивается и вызывает функцию, которую вы дали с this, установленным в заданный вами контекст, передавая любые заданные аргументы. (Это делается выше с помощью Function#apply, который является стандартной частью JavaScript.) Обычно вы бы хотели определить bind на довольно высоком уровне (на уровне страницы или в вашей функции определения объема, если вы используете одну [которая является хорошая идея]), чтобы сгенерированные функции не закрывали больше данных, чем необходимо.

Вот пост в моем анемичном блоге о this более подробно.


Относительно вашего редактирования: На самом деле это совершенно другой вопрос. По умолчанию Ajax-вызовы асинхронны (поэтому Google хочет, чтобы вы предоставили функцию обратного вызова). Таким образом, ваш код запрашивает данные через getLocations, но этот запрос обрабатывается асинхронно, и ваш код продолжается. Следующее, что делает ваш код, это отображает значения, которых у вас еще нет. Через некоторое время запрос будет выполнен, а значения будут обновлены, но к тому времени ваш код завершится. Вы хотели бы переместить предупреждение (в более общем смысле, переместить код, обрабатывающий результат) в обратный вызов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...