BrainLikeADullPencil
BrainLikeADullPencil

Reputation: 11663

calling a javascript function without parenthesis

The following renderChat function is used to render a message and an image onto a chat board. Inside the function there is another function

var onComplete = function () {

which does all the work of creating the list element and appending it to the chat list. After the onComplete function, there is only this three lines of code

  img.onload = onComplete;
  img.onerror = onComplete;
  img.src = c.chat.value.media;

Because the var onComplete is a function assigned to a variable, I assumed it had to be called with parenthesis. Thus, when I see this

img.onload = onComplete;

I understand that the function has been assigned to a new variable, but has never been called. Yet, when I use the application, the chat has been rendered by the time we reach img.src = c.chat.value.media;

Can you please explain how my understanding of JavaScript is mistaken and how this function is working?

 var renderChat = function (c) {
    debug("Rendering chat: key='%s' fingerprint='%s' message='%s' created='%s' imageMd5='%s'",
      c.chat.key,
      c.chat.value.fingerprint,
      c.chat.value.message,
      c.chat.value.created,
      md5(c.chat.value.media));
    var renderFP = c.chat.value.fingerprint;

    if (!isMuted(renderFP)) {
      var img = new Image();
      var onComplete = function () {
        // Don't want duplicates and don't want muted messages
        if (body.find('li[data-key="' + c.chat.key + '"]').length === 0 &&
            !isMuted(renderFP)) {

          var li = document.createElement('li');
          li.dataset.action = 'chat-message';
          li.dataset.key = c.chat.key;
          li.dataset.fingerprint = renderFP;
          li.appendChild(img);

          // This is likely your own fingerprint so you don't mute yourself. Unless you're weird.
          if (userId.val() !== renderFP) {
            updateNotificationCount();

            var btn = document.createElement('button');
            btn.textContent = 'mute';
            btn.className = 'mute';
            li.appendChild(btn);
          }

          var message = document.createElement('p');
          message.textContent = c.chat.value.message;
          message.innerHTML = transform(message.innerHTML);
          li.appendChild(message);

          var createdDate = moment(new Date(c.chat.value.created));
          var timestamp = document.createElement('time');
          timestamp.setAttribute('datetime', createdDate.toISOString());
          timestamp.textContent = createdDate.format('LT');
          timestamp.className = 'timestamp';
          li.appendChild(timestamp);

          var size = addChat.is(":visible") ? addChat[0].getBoundingClientRect().bottom : $(window).innerHeight();
          var last = chatList[0].lastChild;
          var bottom = last ? last.getBoundingClientRect().bottom : 0;
          var follow = bottom < size + 50;

          chatList.append(li);
          setupWaypoints(li);
          debug('Appended chat %s', c.chat.key);

          // if scrolled to bottom of window then scroll the new thing into view
          // otherwise, you are reading the history... allow user to scroll up.
          if (follow) {
            var children = chatList.children();
            if (children.length > CHAT_LIMIT) {
              children.first().remove().waypoint('destroy');
            }

            li.scrollIntoView();
          }
        }
      };

      img.onload = onComplete;
      img.onerror = onComplete;
      img.src = c.chat.value.media;
    }
  };

Upvotes: 0

Views: 262

Answers (3)

cgross
cgross

Reputation: 1952

In Javascript you can store functions in variables, this is what you did with onComplete(). The img object will execute a function(so called callback) after successfully loading the image (onload) or if it could not load the image(onerror).

To tell the img object which method to call after those events, you need to give it the method name like this without parenthesis:

  img.onload = onComplete;
  img.onerror = onComplete;

If you would use parenthesis the function would be executed immediately and img.onload wouldn't contain a reference to a function but the result of onCompleted.

Upvotes: 1

Eugen Rieck
Eugen Rieck

Reputation: 65274

img.onload = onComplete; will assign the function onComplete to the onload handler. THis means, that the function is called, when the vent happens.

img.onload = onComplete(); will assign the result of calling the function onComplete to the onload handler. This means, that the function is called immediately, is expected to return another function (or a string containing valid JS), which in turn will be called when the event happens.

Upvotes: 0

Quentin
Quentin

Reputation: 943579

The HTMLImageElement object will cause functions assigned to its onload and onerror properties to be called at the appropriate times (i.e. when the HTTP response is received or the wait for it times out).

The code to do this is built into the browser. The properties (or the addEventListener function in more modern code) are the only ways with which you can interact with that code.

Upvotes: 1

Related Questions