JSONP回调变量提升,范围异常

时间:2015-06-30 14:33:05

标签: jquery callback scope jsonp hoisting

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

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

这里发生了什么?

screenshot of console

我似乎误解了变量是如何从JASONP回调中确定范围的。有人可以启发我(按照超级非专业人士的说法)关于这里发生了什么,并告诉我这应该是什么样的?

JSFiddle here - 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

谢谢。

1 个答案:

答案 0 :(得分:1)

此代码:

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回调中的任何内容都不依赖于在回调发生之前会发生变化的内容,因为每次调用furl回调都会创建一个新的独立forEach