This course has been updated! We now recommend you take the The Good Parts of JavaScript and the Web course.
Transcript from the "Background on Functions" Lesson
[00:00:00]
>> [MUSIC]
[00:00:04]
>> Douglas Crockford: Okay, act three, functions. So JavaScript has functions. In other languages you've got methods, classes, constructors, modules and other stuff. JavaScript just has functions. So it uses one construct, one concept to do all of these things. That's because functions are really powerful, they can do all of these things.
[00:00:30] So we'll start with syntax. We have a function expression which creates a function value, a function object, a function executable, the thing that it returns you can then invoke. So it starts with the keyword function. It can take an optional name. The name is used to allow the function to call itself recursively, the name is also used by the debugger.
[00:00:53] So, usually the most useful reason to put the name there is so that when you're looking at the stack traces, you can see where you were. Then it can take a set of parameters wrapped in parentheses and then a body that's wrapped in curly braces containing some statements.
[00:01:16] So it will produce an instance of a function object. Function objects are first class, which means they can be passed as arguments to a function, they can be returned from a function, can be assigned from a variable, may be stored in an object or array. So you can use functions just like we use numbers.
[00:01:33] They go everywhere, they can be passed around, which is an unusual thing. In Java, you tend not to pass methods around. But in JavaScript it's very easy to pass functions. And functions being objects, they inherit from Function.prototype. Since Function.prototype has functions on it. Essentially it means every function has methods.
[00:01:58]
>> Douglas Crockford: Functions have a declare statement which declares and initializes variables defined within the function. We don't specify types at that point because we are a loosely typed language. We just declare that something's a function and we don't say, or we declare that something is variable, we don't declare what kinds of variables it will contain.
[00:02:18] And a variable declared anywhere within a function is visible everywhere within the function. So you could declare something in an innermost block. It's going to be visible outside of that block.
>> Douglas Crockford: We talked about that earlier, I think I'll skip it. Okay, to make things more confusing, there's also a function statement, and this is often the thing that people use.
[00:02:41] And the thing that's unfortunate is they look identical. So the function statement also has the keyword function. The name, in this case, is mandatory. You have to supply the name of the function, but it has the same parameters and the same body. So the function statement, function foo() is short-hand for creating a variable, receiving the function expression of function foo().
[00:03:17]
>> Douglas Crockford: So function expression and function statement, it's a little confusing. If the first token of a statement is function, then it is a function statement. In the standard they're not even called function statements, they're called function declarations, but they're commonly called function statements. And one of the limitations of function statements is they have to be declared at the top level of a function, they can't be inside of a block.
[00:03:45] And that's because they do this weird hoisting thing, so putting a function inside of an if statement doesn't make sense. Now it turns out all JavaScript engines try to make some sense out of that, but they all do something different so there's not a reliable form there. We talked about block scope and function scope,
[00:04:12]
>> Douglas Crockford: So I don't think we need to that again. So declare all your variables at the top of the function, and declare all of your functions before you call them. The language provides mechanisms to allow you to ignore that advice, but it's weird. In languages in which functions are static things, then the ordering doesn't make much difference, but in JavaScript, functions are dynamic things.
[00:04:34] And so something happens when the function statement gets executed. So because of that, confusion can occur if you don't respect the order in which things happen.
>> Douglas Crockford: We have a return statement which has two forms. You can either return the result of an expression or return nothing. You don't actually return nothing, you're returning undefined.
[00:04:57] So every function always returns something when it finishes.
>> Douglas Crockford: And in addition to variables and parameters, each function receives two pseudo parameters, arguments and this. Arguments is an array-like thing containing all the arguments that were actually passed to a function. It is array-like in that it has a length operator or length property, but otherwise it is not an array.
[00:05:29] And in some engines there's a weird interaction between this and the actual parameters, so that if you change a value in the arguments array, the corresponding parameter also changes. The makers of JavaScript engines hate this, because it makes it really hard to make their code be fast and efficient when there's any possibility of variables suddenly changing unexpectedly.
[00:05:58] So we can use arguments for doing functions with variable numbers of arguments. So here, I want to write a sum function which will go through some undetermined number of parameters. We can loop through arguments for each element of it, add things up, and return a sum. So is this a good time to break?
[00:06:18]
>> Speaker 2: Yeah.
>> Douglas Crockford: Okay, so let's stop here for an hour or so for lunch, and then we'll finish up.
>> Douglas Crockford: Okay, it's time to talk about this.
>> Douglas Crockford: The this parameter or pseudo parameter, contains a reference to an object of invocation. This is one of the big code reuse ideas in JavaScript, where we can have a single inherited function which can work on many, many objects and the way that function knows which object it is currently working on is by the this binding.
[00:06:49] This allows a method to know what object it is concerned with. And it is the key to prototypal inheritance. Then we have the invocation operator, the brackets or the parens, which is a suffix operator surrounding zero or more comma separated arguments, and each of those arguments will be bound to parameters.
[00:07:11] If the function is called with too many arguments, the extra arguments are ignored. And if a function is called with too few arguments, the missing ones will be set to undefined. There is no implicit type checking on the arguments, but all of the arguments will be passed through the arguments array, even if there were more or less than were indicated by the parameters.
[00:07:33] There are four ways to call a function, four forms of invocation. The function form, the method form, the constructor form and the apply form. So we'll start with the method form. In the method form we have an object. Then something that designates the method, and then the arguments.
[00:07:55] When a function is called in the method form, this is set to this object, which is the object containing the function or inheriting the function. This allows methods to have a reference to the object of interest. Then there is function form. Function form looks the same except it doesn't have the prefix on it that indicates a specific object.
[00:08:17] When a function is called with a function form this is bound to the global object, which turned out was a big mistake in the language. It was fixed in ES5 strict. Going into the future, this will be bound to undefined instead, which still isn't perfect but it's much less wrong than being bound to the global object.
[00:08:40] An inter function does not get access to the this of an outer function, which is sometimes a problem. If you have a method with an internal helper method, or helper function, that helper function doesn't get access to the method's this, because every function gets its own this. So the work around is to have the outer function create its own variable called that, bind this to that, and that is then available to the inner function.
[00:09:10] Then there's constructor form that looks just like the function form except that it has the new prefix. When a function is called with the new operator, a new object is created and assigned to this. And if there is not an explicit return value, then this will be returned.
[00:09:26] And this is used in the pseudo classical style. We'll get to that in a little bit. And finally there's the apply form, in which a function is called through its apply or call method, and in this case, this object is explicitly passed in. And this allows you to save now for this call, this function, this is what this will be.
[00:09:52] So this the summary in a chart. What this will be depends on the invocation form. If it's called as a function, it will be either the global object or undefined, depending on what version of the language you're running in. If it's a method, it will be the object of interest.
[00:10:13] If it's a constructor, it will be a new object. And if it's the apply form, you explicitly say what it's going to be as an argument. Functions in JavaScript have side effects which makes them different than mathematical functions which don't. And it turns out having side effects makes some things harder to reason about but makes other things much easier to reason about.
[00:10:38] We'll talk more about this later in the afternoon in the monad talk.