Check out a free preview of the full JavaScript the Good Parts course:
The "Avoiding Confusing Code (A)" Lesson is part of the full, JavaScript the Good Parts course featured in this preview video. Here's what you'd learn in this lesson:

Confusing code should be avoided. Use programming forms that avoid adding confusion. Looking at block scope versus function scope reveal common pitfalls with variable scope.

Get Unlimited Access Now

Transcript from the "Avoiding Confusing Code (A)" Lesson

[00:00:00]
>> [MUSIC]

[00:00:04]
>> Douglas Crockford: Confusion is where bugs come from. When we think a program does one thing, and it actually does something else, that's what confusion is. That's what creates bugs, right? So we want to eliminate as much confusion as possible, we want to be as clear as possible. We want our programs to be something that you can easily reason about.

[00:00:29] Another of the design areas in JavaScript was the double equal operator, which is supposed to be the equality operator. Unfortunately, it does type coercion before it does its comparison. And so it can get false positives, and you can also lose transitivity. Transitivity is one of the mathematical properties of a language which is supposed to make it easier to reason about, but it actually makes this language harder to reason about because it's not there.

[00:00:56] Fortunately, we have a triple equal operator, which always does the right thing except for nan and we'll talk about that later. But for all of these it'll produce false, which is the correct answer. So my advice is always use triple equal, never use double equal. And if you do that, then there's a whole lot of confusion which disappears and your programs become more reliable.

[00:01:23] Now what about the case where double equal actually, accidentally sort of does the right thing? Should you use it then? And my advice is no, because you wanna make it clear to the reader that you know what you're doing and you're doing the right thing. And so if they see a double equal in your program, they're gonna have to stop and ask, okay, is this a common error, or does this guy actually know what he´s doing?

[00:01:48] It's harder to make the second argument if you're using this operator, so don't do it. So if there's a feature of the language that is sometimes problematic aand if it can be replaced by another feature that is more reliable, then always use the more reliable feature. That will tend to help us keep the error rate down.

[00:02:11] This is a new feature in JavaScript, it was added in the fifth edition, you see this in a lot of other languages. I think this was a mistake, for two reasons. One is that indentation is a really important component of style, because we have a lot of nested functions, nested objects.

[00:02:29] Nesting is very important to revealing the structure of the program and helping us to interpret what is going on. And this breaks indentation, cuz everything has to go back out to the margin. So it does make programs harder to read, harder to understand. And that's a bad thing.

[00:02:45] But even worse, there is a syntactic danger that this statement is correct, and this one is a syntax error. Can anybody spot the syntax error?
>> Speaker 2: Space on the right slash.
>> Douglas Crockford: Yeah, exactly. There's a space right here. It's obvious once it's pointed out, right? But yeah, that causes syntax error.

[00:03:09] So I don't want to use this, because I want my programs to be obviously correct. And if I'm using forms that you cannot distinguish from common errors, then my programs are harder to understand, and I don't want that. So avoid forms that are difficult to distinguish from common errors.

[00:03:29] This is something that was wrong in b, was right in Java but skipped a generation, now it's wrong in JavaScript. We have here if a equals b, which looks like it means this, but it actually means that. So when someone comes and reads the program and sees that in it, you have to ask, okay, what's going on here?

[00:03:54] The only thing they know for sure is that the programmer was incompetent. That they don't really know what this was supposed to do. So my advice is figure out which of these you intended and write that instead. And don't write the form which is ambiguous. Because anytime you have something that looks like one thing that does something else, that's where errors come from.

[00:04:15] Not every time, but often enough that it's a pattern you want to avoid. So make your programs look like what they do.
>> Douglas Crockford: Scope is one of the best inventions in programming languages. It came into the world in ALGOL 60, which was, by far, the best design by committee in the history of programming languages.

[00:04:37] ALGOL 60 was an amazing leap forward. And one of the leaps was block scope, where you could create variables in a block, and they would not be visible outside of the block. And you could nest blocks, and the inner most block would have access to the variables of the outer block, and that was brilliant.

[00:04:56] And it's a feature of almost all programming languages except JavaScript. JavaScript surprisingly does not have block scope, it has function scope, which means anything declared in a function is not visible outside of the function. Now it turns out, that's enough. You can write good programms in a language that has function scope.

[00:05:16] And so it's completely adequate. The problem is that JavaScript has syntax, which is identical to block scope languages. And so, when people come to JavaScript from Java or C or C++ or C# or virtually all other languages, they get confused, because it looks like the same style, but it doesn't work.

[00:05:40] So the reason for this the way the VAR statement works. The VAR statement gets split into two parts, the definition part and the initialization part. If you don't have an initialization part, it synthesizes one using undefined. And it moves the declaration part to the top of the function, what they call hoisting.

[00:06:06] So you might think that you're declaring a variable inside of a block, but it actually gets moved to the top of the function. And this can cause errors. It doesn't always cause errors, but it does cause errors. So you shouldn't rely on that. So in a block scoped language, the best advice is declare the variable in the innermost block where it makes sense to, probably at the site of first use.

[00:06:37] That's good advice in a block scoped language, it's bad advice in a function scoped language. In a function scoped language, you want to declare all of your variables at the top of the functions, because that's where they're actually being declared. So you wanna make it easier for someone to understand what the program is doing by having it match what's actually being done.

[00:06:59] So in JavaScript, declare all of your variables at the top of the function. There's an even weirder thing that happens to function statements, and so for them, I recommend declare all of your functions before you call them. I find this is the most difficult style thing for programmers to accept.

[00:07:18] I've seen some of the best programmers in the world get hung up on this. So the induction variable is not scoped to the loop in JavaScript, it's scoped to the function. So you should move that var i to the top of the function. And I see people get really upset about this.

[00:07:38] And that's wrong, no, it's actually right. Because there are a lot of errors that can occur if you're not aware of that hoisting. And so you really should, you can avoid all of that if you just move them to the top. And you'll say, but this is how you write it in Java!

[00:07:54] And I say, write in the language you're writing in. JavaScript isn't Java. And so there are things that are smart to do in JavaScript that are not smart to do, or smart to do in Java that are not smart to do in JavaScript. So you need to be working in the language you're working in.

[00:08:11] Every language is different. And some of our style conventions can easily translate from one language to another. But it's guaranteed not all of them will. And so you really have to re-address your style for each language that you're working with. In the next edition of JavaScript, there will probably be a let statement.

[00:08:33] And the let statement will be just like the VAR statement, except it will not hoist, which means it will respect block scope.
>> Douglas Crockford: Now at that time on that happy day, my advice will change. And I will say, always use the let statement and never use the VAR statement, unless you have to run on IE6.

[00:08:54]
>> [LAUGH]
>> Douglas Crockford: Or IE7, or IE8, or IE9, or IE10. And we don't know what's in IE11 yet, but pretty sure if you only have to run on IE12 and above, then you'll want to use let statement. Otherwise, you're gonna have to keep using the VAR statement.