JSONP回调变量提升,作用域异常

JSONP Callback variable hoisting, scoping anomoly

我有一个全局数组,我想用 Flickr 上 JPEG 的 URL 填充。我打算在函数之间传递这个数组。

当我尝试从我的 JASONP 回调函数中读取数组(或 main.js:40 中的 console.log)的内容时,它似乎是空的。然而从浏览器控制台来看它似乎很好(屏幕截图)。我的 JASONP 回调似乎能够 array.push() 但无法读取 array[i].src

这是怎么回事?

我似乎误解了 JASONP 回调中变量的范围。有人可以启发我(用超级菜鸟外行的话说)这里发生了什么,并告诉我这应该是什么样子?

这里是 JSFiddle - http://jsfiddle.net/Nyquist212/7gtxetxj/

function UrlExists(url, callback) {
    var http = new XMLHttpRequest();
    http.open('HEAD', url);
    http.onreadystatechange = function() {
        if (this.readyState == this.DONE) {
            callback(this.status = 200);
        }
    };
    http.send();
};

var images = []; // Store imgs in here

$.getJSON("https://api.flickr.com/services/rest/?method=flickr.photos.search&jsoncallback=?",
      { 
          api_key : "da2015d88b5eab3b3d7d989c13c4d430",
          content_type : 1,
          text : "landscape, beach, coast, surf, black, white",
          format : "json",
          per_page : 10
      },

      function jsonFlickrApi (results) { // my JSONP callback func 

            for (var i=0; i < results.photos.photo.length; i++) {
                var farm    = results.photos.photo[i].farm;
                var id      = results.photos.photo[i].id;
                var server  = results.photos.photo[i].server;
                var secret  = results.photos.photo[i].secret;
                var furl    = "https://farm" + farm + ".staticflickr.com/" + server + "/" + id + "_" + secret + "_m" + ".jpg";

                if (!UrlExists(furl, mycallback)) {
                    function mycallback(results){
                        images.push({"src":furl}); 
                        };
                    $("<img />").attr("src", furl).appendTo("#one");              // This works...
                    //$("<img />").attr("src", images[i].src).appendTo("#one");   // Why wont this work?
                }; 
            }; // End for 

            console.log(images); // Returns empty!?!

      } // End jsonFlickrApi
); // End getJSON

谢谢。

此代码:

if (!UrlExists(furl, mycallback)) {
    function mycallback(results) {
        images.push({
            "src": furl
        });
    };
    $("<img />").attr("src", furl).appendTo("#one"); // This works...
    //$("<img />").attr("src", images[i].src).appendTo("#one");   // Why wont this work?
};

从不 调用 mycallback 函数,因此不会向 images 添加任何内容。 (另请注意,不要将 ; 放在附加到控制流语句(如 if)的块的结束 } 之后。)

假设 UrlExists 期望您出于某种原因将回调传递给它并异步调用该回调,您需要实际将函数传递给它,并且您需要确保当函数被调用时,它是用正确的 furl 调用的(因为如果它被调用为异步的,您当前使用的 furl 将在调用回调之前被更改)。注释掉的代码中的 i 也是如此。有了这些假设,您可以这样做:

function jsonFlickrApi(results) { // my JSONP callback func 

    results.photos.photo.forEach(function(photo) {
        var furl = "https://farm" + photo.farm +
                   ".staticflickr.com/" +
                   photo.server + "/" +
                   photo.id + "_" +
                   photo.secret + "_m" + ".jpg";
        UrlExists(furl, function() {  // I assume this is called if the URL does exist, and that that's what you want 
            images.push({
                "src": furl
            });
            $("<img />").attr("src", furl).appendTo("#one");
        });
    });

    // Note that `images` will still be empty here, waiting for the callbacks
    // from UrlExists

} // End jsonFlickrApi

现在,UrlExists 回调中没有任何内容依赖于在回调发生之前会改变的东西,因为每次调用 forEach 都会创建一个新的、单独的 furl回调。