Check out a free preview of the full The Good Parts of JavaScript and the Web course
The "Function Best Practices" Lesson is part of the full, The Good Parts of JavaScript and the Web course featured in this preview video. Here's what you'd learn in this lesson:
Doug spends a few minutes explaining a few best practices when working with JavaScript functions. He talks about avoiding creating functions inside loops. Doug also demonstrates the four ways to call a function.
Transcript from the "Function Best Practices" Lesson
[00:00:00]
>> [MUSIC]
[00:00:04]
>> Douglas Crockford: JavaScript functions have return statements return statement stops the execution of the function returns control to the caller and can also optionally return a value. Return statement contained can take an expression and will evaluate the expression return its value or you can have a return statement that returns nothing.
[00:00:24]
It will actually return the value undefined or if the function falls through the bottom, it will return the undefined value.
>> Douglas Crockford: I recommend that you not make function objects in a loop. It can be wasteful, because every new function object is created on every iteration, so that could be expensive.
[00:00:43]
It can also be confusing, because the new function closes over the loops variables not over their current values and that confusion can lead to bugs. For example, here we've got a for loop, which is going to loop over an array of divs and it's gonna add a click handler to each one, which when clicked on will alert the id of the div and this code looks very straightforward, but it will fail.
[00:01:11]
And the way it fails is no matter which div you click on, they will all display the same id. It'll be the last one and it's because what's being captured by the inner function is the current value of div.id not not the value of div.id the at the time that the function was created.
[00:01:30]
So the way to get around that is to not use a four loop at all, use four each and will pass in a function, which will receive each div of as an argument and will alert correctly.
>> Douglas Crockford: We invoke functions with the pairing suffix operator, which will surround zero or more comma separated arguments and each of those arguments will be bound to one of the parameters of the function.
[00:01:59]
If a function is called with too many arguments, the extra arguments are ignored. It is not an error. If an argument is called with too few arguments, the missing values will be the undefined value. If there is no explicit type checking on the arguments, on their types or on their numbers.
[00:02:15]
So if you really care about that stuff, you need to check it yourself. Generally, you don't have to. It turns out most of the defaults in JavaScript are right. So that if you don't do checking, it'll usually do the right thing anyway. So in addition to any parameters that are formally defined as part of a function, there are also two bonus pseudo parameters that you can also get access to arguments and this.
[00:02:43]
I don't recommend using either of them, but they're both very popular in the language. So, I'd need to describe them both. I will start with the arguments. When a function is invoked in addition to its parameters, it also gets a special printer called arguments and it contains all of the arguments from the invocation.
[00:03:01]
So everything that got passed in the parens are called the function, every one of those values will be in the arguments array. Now one problem with the arguments array is, it is not really an array, even in the weird way that JavaScript thinks of arrays. It is an array like object.
[00:03:17]
It's an object that has a length property, but it's not a magical length property and it doesn't inherit any of the useful array methods. So, it's a difficult thing to work with. You do get arguments dot length, which will be the number of arguments that were actually passed and there's a weird interaction with the parameters.
[00:03:40]
So if you change arguments sub zero, the first parameter also changes. If you change the second parameter, then argument sub one changes for the people who make JavaScript engines. This is maybe the most hated feature of the language, cuz they're working really hard to try to make it go fast and you can't go fast when you have to mess with behavior like that.
[00:04:03]
So, let me show you an example of how you could use it. So we've got a simple sum function, which will receive some variable number of numbers and it will add them up and return the total. So, we're going to get from arguments that length and the number of things that we're going to add.
[00:04:22]
We're gonna loop through in and we're gonna get each of those arguments, and add it to the total. Notice I didn't include any parameters in some, cuz I didn't need to I could have. But it wasn't necessary, because I'm getting all the material from arguments.
>> Douglas Crockford: So now this is a really difficult thing to have in any language, because it makes the language hard to talk about.
[00:04:51]
It's like pair programming with Abbott and Costello. So, bear with me. So, the this parameter contains a reference to the object of invocation. This allows a method to know what object it is concerned with. This allows a single function object to service many objects and it's the key to prototypal inheritance.
[00:05:13]
>> Douglas Crockford: There are four ways to call a function in JavaScript. The function form, method form, constructor form and apply form, four forms. I think in a well-designed language, there should be one form, but we've got four and the way they vary is in what happens to this. So, let's start with the method form.
[00:05:35]
The method form, we say, some object dot method name or some object bracket, an expression that evaluates to a method name. When we call a function this way, then this will get bound to this object. It allows the method that gets called to know which object it's going to be manipulating.
[00:05:58]
In most languages, the binding of this happens fairly late, but nobody does it as late as JavaScript. Java Script doesn't bind this until the moment of invocation, then there's the function form, which looks the same, except we don't have an object prefix. So, we just have some function value and we call that.
[00:06:20]
In this case, this gets bounced to the global object. It's the thing that is the container of all the global variables and that's a terrible thing, because it's leaking way too much capability. It's a security hazard, it's a reliability hazard. This was sort of fixed in ES5/Strict mode.
[00:06:41]
>> Douglas Crockford: But not completely. In ES5/Strict mode, this gets bound to undefined. So at least we're not binding it to something dangerous, but sometimes it's not what you want either. That if you have an inner function inside of a method, you want the inner function to help the method do its work.
[00:06:59]
But the inner function doesn't get to see this, because the inner function gets called as a function. And so, it's this will be either the global object or undefined. So the workaround is in the outer function, in the method, you create a variable called that assign this to it and then the inner function gets to see that.
[00:07:21]
>> Douglas Crockford: Then there is a constructor form, it looks like the function form, except there is a new prefix. And when a function is called with a new prefix, a new object is created and will be bound to this. And if the constructor function does not have an explicit return value, then this will be the return value and this is used in the pseudo classical style, which will get to in a few minutes.
[00:07:45]
And finally, there is the apply form. In the apply form, you call the apply method of the function object and you get to specify what the value of this is going to be. In addition, you can also provide either an array of arguments or you can provide individual arguments separated by commas.
[00:08:08]
>> Douglas Crockford: So to summarize, there are four invocation forms, function, method, constructor and apply. They each vary according to what they do with this. And again, I don't recommend using this at all, but that's how most people use the language and I'll show you an alternative in a few minutes.
[00:08:27]
So, you all know about recursion. That's when you have a function that is defined in terms of itself or the can call itself really, really important thing. I don't need to tell you about Quicksort, that's one of the important examples of using recursion. JavaScript has a recursion, which is good.
[00:08:46]
If you're not familiar with recursive functions, I highly, highly recommend a book called The Little Lisper, which has been revised. It's now called the Little Schemer. It's based on the Scheme language, but it's not really about scheme. It's about recursive functions and everything in that book can be written in JavaScript and this web page will give you the key to to doing that translation.
[00:09:08]
Highly, highly recommended. This is one of those books that can significantly change the way you think in a really good way.
>> Douglas Crockford: There's another book called The Principles of Programming Languages by RC Tennent and one of his principles is the principle of correspondence in which he talks about how variables are like parameters in some languages.
[00:09:35]
So here, we have two versions of the factorial function and one of them result is a variable and the other the result is a parameter. Otherwise, these two functions do exactly the same thing. And so, this demonstrates the similarity of variables and parameters based on how the function is constructed.
[00:09:54]
The interesting thing about the second function is, it's using an immediately revocable function expression. So here, we have a function, declaration or function of expression, which is creating a new function object, which we then call immediately passing in the one. So in general, we can take any expression and wrap it in a function that will return that expression and call the function immediately and it does the same thing as expression.
[00:10:26]
It's just more verbose, but it does the same thing. Now, turns out this is not true in JavaScript for all values. For example, these and arguments change their meaning when you put them in a different function. So it doesn't work for them, but it works for all other expressions and it works for four statements.
[00:10:48]
You can take any bunch of statements and put them in a function and call immediately and it's says, though, you had executed those statements, except that var function break continue and return change their meaning when you put them in another function. Otherwise, you can do this transformation and there are some interesting things that can happen as a result of being being able to do this.
[00:11:12]
So, this is a feature that you look for in a functional language.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops