简体   繁体   English

AJAX回调和Javascript类变量分配

[英]AJAX Callback and Javascript class variables assignments

I am trying to build a little javascript class for geocoding addresses trough Google Maps API. 我正在尝试通过Google Maps API构建一些用于对地址进行地理编码的javascript类。 I am learning Javascript and AJAX and I still can't figure out how can I initialize class variables trough a callback: 我正在学习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);

Thank you for helping me out! 谢谢您的帮助!

EDIT 编辑

Thanks TJ for your reply. 感谢TJ的回复。 I read your example and your post — things are getting much clearer. 我阅读了您的示例和您的帖子-事情变得越来越清晰。 But I still have an issue. 但是我仍然有一个问题。 Have a look: 看一看:

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]);
}

Why the alert in initialize() pops before the alert in geoCallback(), printing an undefined/undefined? 为什么initialize()中的警报在geoCallback()中的警报之前弹出,并显示未定义/未定义?

What you need to do is ensure that this is set correctly in the callback. 什么,你需要做的就是确保this是在回调中正确设置。 This is sometimes called "binding". 有时称为“绑定”。 Prototype provides Function#bind for this, but it's easy enough to do if you don't use Prototype — define a function that will do the binding for you: Prototype为此提供了Function#bind ,但是如果您不使用Prototype,它很容易做—定义一个将为您进行绑定的函数:

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

and then use it in your initialize call: 然后在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]);
}

(Although I think I'd suggest refactoring a bit so that the caller of geoCode doesn't have to provide the callback at that level.) (尽管我认为我建议您进行一些重构,以便geoCode的调用者不必在该级别提供回调。)

What bind above does is create a closure (a function) that, when called, will turn around and call the function you gave with this set to the context you gave, passing on any arguments that were given. 上面的bind所做的是创建一个闭包(一个函数),当调用该闭包时,它会转回并调用您使用this集合提供的函数到您提供的上下文中,并传递给定的所有参数。 (This is done above via Function#apply , which is a standard part of JavaScript.) You'd normally want to define bind at a fairly high level (page level or within your scoping function if you use one [which is a good idea]) to avoid having the generated functions closing over more data than necessary. (以上操作是通过JavaScript的标准部分Function#apply完成的。)通常,您需要在相当高的级别(页面级别或在范围函数内定义bind ,如果您使用一个[ ]),以避免生成的函数关闭多余的数据。

Here's a post in my anemic blog about this in a bit more detail. 这是我贫乏的博客中有关this的更详细的信息。


Regarding your edit: That's actually a completely different question. 关于您的编辑:这实际上是一个完全不同的问题。 By default, Ajax calls are asynchronous (which is why Google wants you to provide a callback function). 默认情况下,Ajax调用是异步的 (这就是Google希望您提供回调函数的原因)。 So your code requests the data via getLocations , but that request is processed asynchronously and your code continues. 因此,您的代码通过getLocations请求数据,但是该请求被异步处理,您的代码继续。 The very next thing your code does is display the values you don't have yet. 您的代码要做的第二件事是显示您还没有的值。 At some later time, the request will complete and the values will be updated, but by then your code has finished. 稍后,请求将完成并且值将被更新,但是到那时您的代码已经完成。 You'd want to move the alert (more generically, move your code processing the result) into a callback. 您想要将警报(更一般地说,将处理结果的代码移动)移到回调中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM