0

I'm working through the Chrome extension tutorial (full code below). There is one thing I don't understand about this, which is related to line 3 of the requestKittens method

        req.onload = this.showPhotos_.bind(this);

and line 1 of the showPhotos method:

        var kittens = e.target.responseXML.querySelectorAll('photo');

I'm trying to understand how e.target.responseXML points to the response XML of the request. Here's what I think so far: In the line that calls this function (3rd line of requestKittens()), this points to the kittenGenerator object, meaning that kittenGenerator is bound as the first argument for showPhotos(). So the argument e in showPhotos() should be kittenGenerator, right?

If that's true, then the first line of showPhotos()...

var kittens = e.target.responseXML.querySelectorAll('photo');

...is saying that kittenGenerator has a property target. However I checked this in the Chrome console and it doesn't - so there's a mistake in my logic. Anyone able to help?

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * Global variable containing the query we'd like to pass to Flickr. In this
 * case, kittens!
 *
 * @type {string}
 */
var QUERY = 'kittens';

var kittenGenerator = {
  /**
   * Flickr URL that will give us lots and lots of whatever we're looking for.
   *
   * See http://www.flickr.com/services/api/flickr.photos.search.html for
   * details about the construction of this URL.
   *
   * @type {string}
   * @private
   */
  searchOnFlickr_: 'https://secure.flickr.com/services/rest/?' +
      'method=flickr.photos.search&' +
      'api_key=90485e931f687a9b9c2a66bf58a3861a&' +
      'text=' + encodeURIComponent(QUERY) + '&' +
      'safe_search=1&' +
      'content_type=1&' +
      'sort=interestingness-desc&' +
      'per_page=20',

  /**
   * Sends an XHR GET request to grab photos of lots and lots of kittens. The
   * XHR's 'onload' event is hooks up to the 'showPhotos_' method.
   *
   * @public
   */
  requestKittens: function() {
    var req = new XMLHttpRequest();
    req.open("GET", this.searchOnFlickr_, true);
    req.onload = this.showPhotos_.bind(this);
    req.send(null);
  },

  /**
   * Handle the 'onload' event of our kitten XHR request, generated in
   * 'requestKittens', by generating 'img' elements, and stuffing them into
   * the document for display.
   *
   * @param {ProgressEvent} e The XHR ProgressEvent.
   * @private
   */
  showPhotos_: function (e) {
    var kittens = e.target.responseXML.querySelectorAll('photo');
    for (var i = 0; i < kittens.length; i++) {
      var img = document.createElement('img');
      img.src = this.constructKittenURL_(kittens[i]);
      img.setAttribute('alt', kittens[i].getAttribute('title'));
      document.body.appendChild(img);
    }
  },

  /**
   * Given a photo, construct a URL using the method outlined at
   * http://www.flickr.com/services/api/misc.urlKittenl
   *
   * @param {DOMElement} A kitten.
   * @return {string} The kitten's URL.
   * @private
   */
  constructKittenURL_: function (photo) {
    return "http://farm" + photo.getAttribute("farm") +
        ".static.flickr.com/" + photo.getAttribute("server") +
        "/" + photo.getAttribute("id") +
        "_" + photo.getAttribute("secret") +
        "_s.jpg";
  }
};

// Run our kitten generation script as soon as the document's DOM is ready.
document.addEventListener('DOMContentLoaded', function () {
  kittenGenerator.requestKittens();
});
guzman
  • 167
  • 2
  • 11
  • e is the event parameter and `e.target` points to the object on which the event `onload` is fired which is `req` object. – gp. Oct 19 '14 at 10:09
  • You need to remember that `.bind()` takes a `thisArg` before the list of bound arguments, which is what the `this` value within the function will be bound to. – Qantas 94 Heavy Oct 19 '14 at 10:11
  • http://stackoverflow.com/questions/4195970/what-does-this-mean – Paul Oct 19 '14 at 10:27

1 Answers1

0

The first parameter of bind defines the context of partial application.

req.onload = this.showPhotos_.bind(this);

works because XMLHttpRequest uses event as its first parameter on it's onload handler. That's where e.target comes from.

To give you a simple example of bind, consider the following:

function add(a, b) {
    return a + b;
}

var addTwo = add.bind(null, 2);
addTwo(10); // yields 12

If you define a context for bind (ie. something else than null), then you can access that context using this within the function.

Juho Vepsäläinen
  • 24,765
  • 11
  • 73
  • 98
  • Ah ok, so in the line... `req.onload = this.showPhotos_.bind(this);` ...`kittenGenerator.showPhotos()` is set to execute upon onload, but with `this` set to equal the `this` in the context of that line, which equals `kittenGenerator`. Is that correct? – guzman Oct 19 '14 at 13:22
  • Yeah. That's the point. This is the reason why I prefer to avoid using `this` as it just adds unnecessary confusion to code. – Juho Vepsäläinen Oct 19 '14 at 14:55
  • The other confusing part of this is that `onload` automatically uses the event as a parameter in the function assigned... I played about with this in the chrome console and think I get it now, but pretty odd. Anyway, thanks for the help. – guzman Oct 19 '14 at 18:00
  • Yeah. That's due the way `XMLHttpRequest` API has been specified. See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest for some nice extra info. – Juho Vepsäläinen Oct 19 '14 at 18:12