Script Tags
So far we've been working with the JavaScript console, which is a great way to try out code and experiment, but obviously most web pages do not write their scripts this way. We need to learn how to embed scripts into web pages, which means using the <script> tag. But don't worry: the console is still going to be extremely useful to us.
The <script> tag tells the browser to load and execute a piece of JavaScript code. There are two ways to do so, either by writing code directly on the page between the opening and closing tag, or using the src attribute to include it from an external file (pretty much exactly the same way as the <img> tag). Here's an example of each:
<script>
var x = 12;
</script>
<script src="external.js"></script>
You may notice that in both cases, there's a closing tag, even if there is no code inside. This is an unfortunate quirk of the script tag. You must include a separate "</script>" after opening the tag, and the tag cannot be self-closing (as in "<script />"). Also, if you include an external script tag, don't try to write any extra code between the tags--the browser will just ignore it.
Sometimes people include a type attribute on their tag (typically it's type="text/javascript" or something similar). This isn't necessary: the only language that runs in the browser is JavaScript, so a plain <script> tag will be interpreted that way by default. More importantly, a typo in the type attribute may cause the browser to not run your code, so it's safer just to leave it off.
Adding code to an HTML page using <script> tags is convenient, but it means that we might sometimes get lost in large blocks of code. Sometimes we want to add comments to our code in English, in order to explain a particularly tricky line or even just to leave ourselves (and other programmers) a note about why we wrote it that way. There are two ways to leave comments in JavaScript. The first is to put a // in front of the line, and the second is to wrap the text in /* and */ markers.
// this is a code comment
// I can write anything I want here, and it won't be run as JavaScript.
var code = "JavaScript"; //I can add comments after lines of code
/*
This is a multi-line comment.
Everything between the markers
on the outside will be a
comment as well.
*/
Unfortunately, when we run code from inside of a script tag like this, we lose the ability to immediately see its evaluated result the way we can when we type each line into the console. We'll need a way to print information to the screen from our script, so that we can see the output of our scripts. For that, we're going to use a command that's attached to the built-in console variable, named console.log(). We can put any expression between the parentheses, and it will be evaluated and printed out on the console for us. Try making a script tag (embedded or external) and including a few log statements, like so:
console.log("Hello, world!");
console.log(true);
console.log(123.45);
Like the String() and Number() converters, console.log() is also a function (note the parentheses on the end). Remember, functions are special commands that take their inputs between their trailing parentheses. You can provide multiple inputs to console.log(), or any other function, by listing them one at a time, separated by commas. Not all functions will actually do something with the extra input, but this one will:
console.log("Hello", 123, true);
//logs "Hello" 123 true
Using the console for logging will be an important way to check what your script is doing, even after we learn to write to the page for output, because it's not exposed to ordinary page visitors. You can log any errors or information you want to the console during development, and not worry that people using your site are seeing your debugging messages. In some older browsers, however, using the console log without having the developer tools open is an error, so you should remove your log messages before putting the page into public use.
Conditionals
So far, we have only written expressions, stored those values in variables, and used those variables in other expressions. These are good building blocks, but they're not much more than a very fancy calculator could do. For our scripts to be really useful, they should be able to make decisions based on those values. That's where conditional statements come in. Here's a very basic conditional:
if (expression) {
console.log("It's true!")
console.log(somethingTrue);
}
It starts with the if keyword, which means exactly what it sounds like it means. Then, in parentheses, we've written an expression consisting of a single variable. If that variable is true, all the code between the curly braces will be executed (in this case, logging the string "It's true!" and the value of somethingTrue), and if it is false, it gets skipped (nothing happens). Curly braces indicate a "block" in JavaScript, collecting several lines of code into a single unit.
The existence of Boolean values should start to make a bit more sense now: they're useful for making choices. But technically, JavaScript is not so picky about the values it considers "true"--or more specifically, what it considers "false." The following values are equivalent to false when evaluated inside the parentheses of an if statement:
- "" (i.e., an "empty" string with nothing in it)
- false
- 0 (but only as a number, not "0" as a string)
- null
- undefined
- NaN
Three of these are values we're not terribly familiar with yet. We have not talked much about null so far, and we'll probably stay away from it in the future. It's a special value used to indicate a result of no value, which is uncommon. NaN, as we saw earlier, is an error value that results when you try to subtract a string or perform another math operation on a non-numerical value. undefined is another special value: it's the value that all variables start with before they're assigned a value. We haven't seen undefined before, because we've been assigning variables as soon as we create them, which is a good practice to get into, but we'll use it later when making lists.
Anything that is not on this list is equivalent to true inside a conditional statement. So, for example, the following statements will all be truthy, even if they look like they shouldn't be at first glance:
if (true) { console.log("True, because it's a literal true value"); }
if ("false") { console.log("True, because it's a string and not a Boolean"); }
if (1) { console.log("True, because it's non-zero"); }
var value = true;
if (value) { console.log("We can test variables, in addition to literals."); }
The second line shows why it's so important to know the difference between a Boolean (false) and a string ("false"). The string will be considered truthy for the purpose of conditionals, so if you really mean false, be sure to leave out the quotes.
In addition to writing raw values, or single variables, into a conditional statement, we can also perform comparisons between two or more values. The comparison operators are generally straightforward, and when placed between two items they result in true or false as laid out in the following table.
Operator | Meaning | Notes | |||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
== | equal to | Performs type conversion: 1 == "1" is true
===
| equal to (strict)
| Does not convert types: 1 === "1" is false
| !=
| not equal to
| Performs type conversion: 1 != "1" is false
| !==
| not equal to (strict)
| Does not convert types: 1 !== "1" is true
| >
| greater than
|
| >=
| greater than or equal to
|
| <
| less than
|
| <=
| less than or equal to
|
| |
All the comparison operators work on both strings and numbers. In strings, the "greater than" and "less than" operators work according to alphabetical order. This can cause some problems, if the values you think are numbers are actually strings--after all, 2 is less than 11, but "2" is greater than "11"! Luckily, this doesn't come up too often, and you can always use the parseInt() function to make sure something is actually a number before the comparison.
var n = 12;
if (n == 12) {
console.log("True!");
}
if (n === "12") {
console.log("Nope.");
}
if (n > 10) {
console.log("Yes, indeed.");
}
In addition to being able to specify a block of code to be executed if the condition is true, we can also specify a block that runs if it is not true. To do so, we follow our if with an else and another section of code in curly braces.
if (name == "Thomas") {
console.log('This executes if the statement is true.');
} else {
console.log("This executes if it's false.");
}
It may be easier to visualize if and if/else using a kind of flowchart. In the interactive graphic below, we represent the two branches of our code with lighbulbs that are wired to our if statement, and you can edit the condition that's written between the parentheses. If the condition is true, the first block executes, and its lightbulb will light up. If the condition is false, you'll see the second bulb light up as the else block executes. If your condition isn't valid, neither light will be turned on--in that case, try your JavaScript on the console and see what error it throws.
console.log('Hello, world!');
placeholder = placeholder + 12;
if () {
} else {
}
console.log("remaining code");
//we now resume normal program flow
So far, all the conditional statements we've created have had only two paths: the if (when the condition is true) and the else (when it's false). But by combining the else with another if, we can actually chain them together to create a more interesting set of conditions:
var x = 12;
if (x > 20) {
//first try one condition
} else if (x < 10) {
//try another condition
} else {
//if all else fails, do this
}
Finally, it's possible to combine or invert multiple conditions into one if statement, using a series of special operators.
&& | AND |
|| | OR |
! | NOT |
By putting the && or || operators between two conditions, you can either require both of them to be true, or specify that either one can be true:
if (true && false) {
//this will not execute, because && means AND:
//both the first AND the second item must be true
}
if (false || true) {
//even thought the first item is false, this block will
//still execute, because either the first OR the second
//item must be true.
}
&& and || behave like our addition or subtraction operators: they go between two items to create an expression. The NOT operator is different. By placing a ! in front of an expression, you flip it from true to false, or from false to true. Be careful with ! as it can create some confusing code.
if (!false) {
//it's NOT false, so it's true
}
These operators are very useful for writing compound conditions, but don't go too crazy with them. Abusing && and || to create long chains of conditional if statements can end up being very hard to read, and sometimes you're better off just nesting if statements inside each other for the same effect.
Example Code
The prompt function lets us ask the user for input, which will be returned as a string (even if they type in a number, so watch out!). For example, the following code asks the user to provide a value, and stores it in the variable named answer.
var answer = prompt('Please type a value');
We can also use the confirm() function to get an answer in true/false form (although the dialog box will usually be labeled with buttons reading "OK" and "Cancel").
var confirmation = confirm("Press OK to set confirmation to 'true.'");
Between prompt(), confirm() and console.log(), we have the required inputs and outputs to write a simple text adventure, like the old "choose your own adventure" books. By nesting our conditional statements inside each other, we can given the story multiple paths and endings. In the following example, we'll retell a well-known fable using JavaScript.