Jump to content
Larry Ullman's Book Forums

Chapter 7 Questions


Recommended Posts

In one of the examples in Chapter 7, Larry includes a rather verbose variable declaration in the script words.js:

 

 

// Sort the words:

var sorted = words.map(function(value) {

return value.toLowerCase();

}).sort();

 

He mentions that iterating the variable assignment into discrete steps may be easier to understand which is the approach that I took. So the code would translate to something like this:

 

 

var sorted= words.map(changeToLowerCase); //invoke changeToLowerCase function

sorted= sorted.sort();

setText('output', sorted.join(', ')); //function call to output words

 

My problem was when I attempted to declare the variable changeToLowerCase as a function definition, the interpreter didn't like it. I had to define it as a separate function to get the script to work. I'm wondering if I may have misunderstood this idea.

 

 

var changeToLowerCase(value)

{return value.toLowerCase();}

 

 

Also, in this chapter, the following is used:

 

window.onload= init;

 

It's explained that the function definition is the proper assignment, not the function call. I'm having a hard time wrapping my head around this idea. I don't understand how the two differ. Anyway, I tried using window.onload= init(); and it seemed to work.

 

Chris

Link to comment
Share on other sites

Wow! Lots of questions.

I guess I'll start at the beginning and go through them one at a time.

 

First off, changeToLowerCase is not a predefined function in JS, so unless you define it yourself, JS will split back an error saying, "I don't know what changeToLowerCase is."

 

You'll notice that in Larry's example, he doesn't use or define a function called changeToLowerCase. Instead, he defines an anonymous function (which doesn't require a name), and uses that as the mechanism for mapping values in one array to another.

Larry does, however, use the toLowerCase() method, which is a predefined method for strings in JS, so that's completely valid.

 

The other interesting thing Larry is doing in his example is chaining method calls together. Not surprisingly, this technique is called chaining, and is a cool feature in JS that is used quite heavily in jQuery. By chaining method calls together, you can use the results of one method call as the input of the next method call, thus allowing you to perform multiple discrete operations on a set of data in one line.

 

Specifically in Larry's example, he calls the map method on the words array, which, as the way Larry defines the anonymous function reference provided as the argument, goes through each value in the words array and makes it lowercase, and then takes the array returned from the map method and feeds that to the sort method, which then alphabetizes (in ASCII order) the array. The array returned from the sort method is the array that's stored in the sorted variable being declared.

 

Something else to note, your changeToLowerCase function definition (shown below) is not valid. Most likely, the browser you are using was able to figure out what you were trying to say, and thus silently fixed the code for you and executed it without throwing an error.

 

var changeToLowerCase(value)
      {return value.toLowerCase();}

 

However, with that said, you should of course define functions the right way. There are two valid ways, both demonstrated below.

 

function changeToLowerCase(value) {

 return value.toLowerCase();

}

var changeToLowerCase = function (value) {

 return value.toLowerCase();

};

 

Please use one or the other, and don't mix up the syntax.

 

To answer your final question, there are function calls and function references. As Larry states, these are very different.

 

A function call causes a function to be immediately executed, upon which operations are performed and something is returned. (Note that in JS, if nothing is explicitly returned by a function, undefined is implicitly returned.)

 

A function reference on the other hand does not cause a function to be called (at least, not immediately). As such, when you assign a function reference (i.e., a function variable without parentheses after it) to an event handler, then you're telling JS to call the function when the event occurs (and not now).

 

If you instead assign a function call to an event handler, then what happens is the function is immediately called and the returned value of the function (not the function definition itself) is assigned to the event handler.

 

As a quick example, imagine the following function definition:

 

function addUp(a,  {

 return a + b;

}

 

Now imagine the following event handler definition:

 

window.onload = addUp(1, 2);

 

Instead of a reference to the addUp function being assigned to the event handler (in other words, instead of telling JS to call the addUp function when the onload event fires for the window object), the addUp function would be called immediately, and the returned value 3 (i.e., 1 + 2) would be assigned to the onload event handler.

Thus, when the onload event fires, JS would attempt to call a function in response to the event, but instead of finding a function reference to call, it would find 3 and basically say, "Ummm... I don't know what to do with this. CRASH!!!"

 

That's why an error occurs when you assign a function call to an event handler. (Strictly speaking, you can assign a function call to an event handler, but within that function call somewhere, a function reference has to be returned at some point so that ultimately, a function reference is assigned to the event handler.)

 

The fact that an error does not occur when you assign init() instead of init to the onload event handler is again most likely a sign that your browser is taking your incorrect code and correcting it silently so that it works without telling you. (And believe me, browsers "try" to fix invalid code all the time, so it's a distinct possibility.) Please don't think that just because your code works that syntax is valid (because it's not; too harsh?!).

 

Anyway, I hope that answers all your questions.

Please let me know.

Thanks.

  • Upvote 2
Link to comment
Share on other sites

Nice compliment, Larry. Thanks.

 

I've been meaning forever to make my own website about developing websites, but "life" keeps getting in the way.

And when I say life, I mean my lovely wife and daughter, which I can't get enough of.

Someday, I suppose, I'll finally get around to writing that "great American (Javascript) novel", but until then, this is my (online) home.

  • Upvote 1
Link to comment
Share on other sites

Nice explanation of the function reference - thanks.

 

A couple of follow up questions: Does this mean that you cannot pass an argument to a function referenced on an event handler - or rather is there a way to pass arguments? Also, is the optional event object (commonly "e") the only available argument to event listener functions?

Link to comment
Share on other sites

Yes, technically, you cannot pass arguments to function references assigned to event handlers, but there's an easy workaround: Simply assign an anonymous function definition/reference to the event handler, and then call whatever function(s) you want within the anonymous function.

 

For example, let's say you wanted to send some random string value to a function when an event fires. As discussed above, the following won't work:

 

window.onload = sliceItUp(str);

 

However, by wrapping the function call in an anonymous function, you could make the function call and everything would be fine. For example:

 

window.onload = function () {

 sliceItUp(str);

};

 

Also, yes, the Event object is the only implicit argument available to event listener functions.

Or rather, I should rephrase that, it's the only additional argument available to event listener functions; you still have access to "this", the "arguments" object, etc.

  • Upvote 1
Link to comment
Share on other sites

 Share

×
×
  • Create New...