我正在尝试构建一个小的javascript类,用于通过Google Maps API对地址进行地理编码。我正在学习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);
感谢您帮助我!
感谢您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()中的警报之前弹出,打印未定义/未定义?
答案 0 :(得分:1)
您需要做的是确保在回调中正确设置this
。这有时被称为“绑定”。 Prototype为此提供了Function#bind
,但是如果你不使用Prototype就很容易做到 - 定义一个能为你做绑定的函数:
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
[这是一个好主意])避免生成的函数关闭超过必要的数据。
Here's a post在我的贫血博客中有关this
的详细信息。
关于你的编辑:这实际上是一个完全不同的问题。默认情况下,Ajax调用是异步(这就是Google希望您提供回调函数的原因)。因此,您的代码通过getLocations
请求数据,但该请求是异步处理的,您的代码仍在继续。您的代码接下来要做的就是显示您还没有的值。稍后,请求将完成,值将更新,但到那时您的代码已完成。您希望移动警报(更一般地,将处理结果的代码移动到回调中)。